From Zarafa wiki
#!/usr/bin/php
<?
/**
* This script can be used to fix all recurring items in Calendar which fall between 25oct to 31oct
* When calling from command line you have to pass usernames in space separated list to the script,
* if you want to fix recurring items for all users then pass "-a" as argument to the script
*
* Usage:
* for selected users
* php fix_recurring_items.php -u <username1> <username2> ...
* for all users
* php fix_recurring_items.php -a
*/
// comment this line for debugging
error_reporting(0);
// mapi include files
include('/usr/share/php/mapi/mapi.util.php');
include('/usr/share/php/mapi/mapidefs.php');
include('/usr/share/php/mapi/mapicode.php');
include('/usr/share/php/mapi/mapitags.php');
include('/usr/share/php/mapi/mapiguid.php');
include('/usr/share/php/mapi/class.recurrence.php');
// config options
$ADMINUSERNAME = "SYSTEM";
$ADMINPASSWORD = "";
$SERVER = "file:///var/run/zarafa";
$USAGEMESSAGE = "Usage:\n\tfor selected users \n\t\tphp fix_recurring_items.php -u <username1> <username2> ...\n\tfor all users \n\t\tphp fix_recurring_items.php -a\n";
// properties
$proptags = Array();
$proptags["entryid"] = PR_ENTRYID;
$proptags["subject"] = PR_SUBJECT;
$proptags["meetingstatus"] = "PT_LONG:PSETID_Appointment:0x8217";
$proptags["commonstart"] = "PT_SYSTIME:PSETID_Common:0x8516";
$proptags["commonend"] = "PT_SYSTIME:PSETID_Common:0x8517";
$proptags["recurring"] = "PT_BOOLEAN:PSETID_Appointment:0x8223";
$proptags["timezone_data"] = "PT_BINARY:PSETID_Appointment:0x8233";
$proptags["clipstart"] = "PT_SYSTIME:PSETID_Appointment:0x8235";
$proptags["clipend"] = "PT_SYSTIME:PSETID_Appointment:0x8236";
$proptags["startrecurdate"] = "PT_LONG:PSETID_Meeting:0xD";
$proptags["startrecurtime"] = "PT_LONG:PSETID_Meeting:0xE";
$proptags["endrecurdate"] = "PT_LONG:PSETID_Meeting:0xF";
$proptags["endrecurtime"] = "PT_LONG:PSETID_Meeting:0x10";
if($argc < 2) {
exit($USAGEMESSAGE);
}
// use SYSTEM account for login
$session = mapi_logon_zarafa($ADMINUSERNAME, $ADMINPASSWORD, $SERVER);
if(!$session) {
exit("Can't login into zarafa server\n");
}
// get all stores of SYSTEM account
$msgStoresTable = mapi_getmsgstorestable($session);
$msgStores = mapi_table_queryallrows($msgStoresTable, array(PR_DEFAULT_STORE, PR_ENTRYID));
// get default store
foreach ($msgStores as $row) {
if($row[PR_DEFAULT_STORE]) {
$storeEntryid = $row[PR_ENTRYID];
}
}
if(!$storeEntryid) {
exit("Can't find default store\n");
}
// open default store
$store = mapi_openmsgstore($session, $storeEntryid);
if(!$store) {
exit("Unable to open system store\n");
}
// set named properties
$GLOBALS['proptags'] = getPropIdsFromStrings($store, $proptags);
if(strcasecmp($argv[1], "-a") == 0) {
// get all zarafa users and remove property data
$userList = array();
// for multi company setup
$companyList = mapi_zarafa_getcompanylist($store);
if(mapi_last_hresult() == NOERROR && is_array($companyList)) {
// multi company setup, get all users from all companies
foreach($companyList as $companyName => $companyData) {
$userList = array_merge($userList, mapi_zarafa_getuserlist($store, $companyData["companyid"]));
}
} else {
// single company setup, get list of all zarafa users
$userList = mapi_zarafa_getuserlist($store);
}
if(count($userList) <= 0) {
exit("Unable to get user list\n");
}
foreach($userList as $userName => $userData) {
// check for valid users
if($userName == "SYSTEM") {
continue;
}
print "Searching recurring items for user - ". $userName . "\n\n";
$result = findRecurringItems($session, $store, $userName);
if($result) {
print $result ." recurring item are fixed for user - " . $userName . "\n\n";
} else {
print "No defective recurring items found for user - " . $userName . "\n\n";
}
}
} else if(strcasecmp($argv[1], "-u") == 0) {
// only clear properties for selected users
if($argc == 2) {
exit("No user specified\n\n" . $USAGEMESSAGE);
}
for($index = 2; $index < $argc; $index++) { // start with argv[2]
print "Searching recurring items for user - ". $argv[$index] . "\n\n";
$result = findRecurringItems($session, $store, $argv[$index]);
if($result) {
print $result ." recurring item are fixed for user - " . $argv[$index] . "\n\n";
} else {
print "No defective recurring items found for user - " . $argv[$index] . "\n\n";
}
}
} else {
exit("Unknown option specified\n\n" . $USAGEMESSAGE);
}
/**************** Internal Functions ******************/
/**
* findRecurringItems
*
* Finds recurring items between 25 Oct to 31 Oct for specified username and store
* @param session mapi session
* @param resource store mapi store of given username
* @param string userName username of user to search for.
* @returns boolean/number false if no recurring item is fixed else no. of recurring items fixed
*/
function findRecurringItems($session, $store, $userName)
{
$result = false;
$itemCount = 0;
// create entryid of user's store
$userStoreEntryId = mapi_msgstore_createentryid($store, $userName);
if(!$userStoreEntryId) {
print "\tError in creating entryid for user's store - " . $userName . "\n";
return false;
}
// open user's store
$userStore = mapi_openmsgstore($session, $userStoreEntryId);
if(!$userStore) {
print "\tError in opening user's store - " . $userName . "\n";
return false;
}
// get user's root store
$userRootStore = mapi_msgstore_openentry($userStore, null);
$userRootStoreProps = mapi_getprops($userRootStore, array(PR_IPM_APPOINTMENT_ENTRYID));
// Open the user's calendar Folder
$userCalendar = mapi_msgstore_openentry($userStore, $userRootStoreProps[PR_IPM_APPOINTMENT_ENTRYID]);
// get rows
$calContentTable = mapi_folder_getcontentstable($userCalendar);
// Restriction to find all recurrings items
$res = Array(RES_AND,
Array(
Array(RES_PROPERTY,
Array(RELOP => RELOP_EQ,
ULPROPTAG => $GLOBALS['proptags']['recurring'],
VALUE => true // Item should be recurring
)
),
Array(RES_PROPERTY,
Array(RELOP => RELOP_GE,
ULPROPTAG => $GLOBALS['proptags']['commonstart'],
VALUE => gmmktime(0, 0, 0, 10, 25, 2010)
)
),
Array(RES_PROPERTY,
Array(RELOP => RELOP_LE,
ULPROPTAG => $GLOBALS['proptags']['commonstart'],
VALUE => gmmktime(0, 0, 0, 11, 1, 2010)
)
)
)
);
$rows = mapi_table_queryallrows($calContentTable, $GLOBALS['proptags'], $res);
// Now loop through each recurring item and find which one is falling in 25 - 31 OCT daterange.
foreach ($rows as $row) {
$result = processRecurringItem($userStore, $row);
if ($result) $itemCount++;
}
return $itemCount ? $itemCount : $result;
}
/**
* processRecurringItem
*
* Checks if given message is broken, if broken then fixes borken properties on message as well as in recurrence blob
* @param resource store mapi store of given username
* @param array itemProps message properties of recurring item
* @return boolean returns true if found broken and fixed else false.
*/
function processRecurringItem($userStore, $itemProps)
{
print "\tProcessing item - '". $itemProps[PR_SUBJECT] ."' \n";
// Open message
$message = mapi_msgstore_openentry($userStore, $itemProps[PR_ENTRYID]);
$recurr = new Recurrence($userStore, $message);
$tz = $recurr->parseTimezone($itemProps[$GLOBALS['proptags']['timezone_data']]);
// Calculate 'ClipStart' based on 'CommonStart'
$localCommonStart = $recurr->fromGMT($tz, $itemProps[$GLOBALS['proptags']['commonstart']]); //Get commonStart in LOCAL time
$clipStart = $recurr->dayStartOf($localCommonStart); //Get start of day of localtime
$clipStart = $recurr->toGMT($tz, $clipStart); //Convert back to GMT time
if ($clipStart != $itemProps[$GLOBALS['proptags']['clipstart']]) {
print "\t\tRecurring item - '". $itemProps[PR_SUBJECT] ."' found broken.\n\t\tFixing - '". $itemProps[PR_SUBJECT] ."'\n";
//This recurring item is broken
$props = Array();
$props[$GLOBALS['proptags']['clipstart']] = $clipStart;
// Calculate 'StartRecurDate' and 'StartRecurTime'
$gmStartDate = $recurr->gmtime($localCommonStart);
$props[$GLOBALS['proptags']['startrecurdate']] = ((intval($gmStartDate['tm_year'], 10)+1900) * 512) + ((intval($gmStartDate['tm_mon'], 10)+1) * 32) + intval($gmStartDate['tm_mday'], 10);
$props[$GLOBALS['proptags']['startrecurtime']] = (intval($gmStartDate['tm_hour'], 10) * 4096) + (intval($gmStartDate['tm_min'], 10) * 64) + intval($gmStartDate['tm_sec'], 10);
// Calculate 'EndRecurDate' and 'EndRecurTime'
$localCommonEnd = $recurr->fromGMT($tz, $itemProps[$GLOBALS['proptags']['commonend']]);
$gmEndDate = $recurr->gmtime($localCommonEnd);
$props[$GLOBALS['proptags']['endrecurdate']] = ((intval($gmEndDate['tm_year'], 10)+1900) * 512) + ((intval($gmEndDate['tm_mon'], 10)+1) * 32) + intval($gmEndDate['tm_mday'], 10);
$props[$GLOBALS['proptags']['endrecurtime']] = (intval($gmEndDate['tm_hour'], 10) * 4096) + (intval($gmEndDate['tm_min'], 10) * 64) + intval($gmEndDate['tm_sec'], 10);
// Calculate Duration
$duration = $localCommonEnd - $localCommonStart;
// Fix 'StartOcc' and 'EndOcc' in recurrence blob
$recurr->recur['startocc'] = ($gmStartDate['tm_hour'] * 60) + ($gmStartDate['tm_min']);
$recurr->recur['endocc'] = $recurr->recur['startocc'] + ($duration / 60);
// Save recurrence
$recurr->saveRecurrence();
// Calculate 'ClipEnd' with the help of 'RecurEnd' and 'EndOcc' from recurr blob.
if ($recurr->recur['term'] != 0x23) { // Do nothing if recurrence doesn' end
$clipEnd = $recurr->recur['end'] + ($recurr->recur['endocc'] * 60);
$clipEnd = $recurr->fromGMT($tz, $clipEnd);
$clipEnd = $recurr->dayStartOf($clipEnd);
$clipEnd = $recurr->toGMT($tz, $clipEnd);
$props[$GLOBALS['proptags']['clipend']] = $clipEnd;
}
// Commit changes
mapi_setprops($message, $props);
mapi_savechanges($message);
print "\t\tRecurring item - '". $itemProps[PR_SUBJECT] ."' is now fixed.\n";
return true;
}
print "\t\tRecurring item - '". $itemProps[PR_SUBJECT] ."' seems good do not need any processing.\n";
print "\n";
return false;
}
?>