Zarafa Alert Script : Recurrent Meeting

From Zarafa wiki

Revision as of 14:37, 27 October 2010 by Zkaat (Talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search
#!/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;
}
?>
Personal tools