<?php
	/**
	 * Addressbook Module
	 */
	class AddressbookListModule extends ListModule
	{	
		/**
		 * Constructor
		 * @param int $id unique id.
		 * @param array $data list of all actions.
		 */
		function AddressbookListModule($id, $data)
		{
			$this->properties = $GLOBALS["properties"]->getContactABProperties();
			$this->ab_properties = $GLOBALS["properties"]->getAddressBookProperties();
		
			parent::ListModule($id, $data, array());
		}
		
		/**
		 * Executes all the actions in the $data variable.
		 * @return boolean true on success of false on fialure.
		 */
		function execute()
		{
			foreach($this->data as $actionType => $action)
			{
				if(isset($actionType)) {
					try {
						$store = $this->getActionStore($action);
						$parententryid = $this->getActionParentEntryID($action);
						$entryid = $this->getActionEntryID($action);

						if(isset($action["subActionType"]) && $action["subActionType"] != "") {
							$subActionType = $action["subActionType"];
						}

						switch($actionType)
						{
							case "list":
								switch($subActionType)
								{
									case "hierarchy":
										$this->getHierarchy($action);
									break;

									case "contacts":
										$this->messageList($store, $entryid, $action, $subActionType);
									break;

									case "globaladdressbook":
										$this->GABUsers($action, $subActionType);
									break;

									default:
										$this->handleUnknownActionType($actionType);
								}
								break;
							default:
								$this->handleUnknownActionType($actionType);
						}
					} catch (MAPIException $e) {
						$this->processException($e, $actionType);
					}
				}
			}
		}
		
		/**
		 * Function which retrieves a list of contacts in a contact folder
		 * @param object $store MAPI Message Store Object
		 * @param string $entryid entryid of the folder
		 * @param array $action the action data, sent by the client
		 * @param string $actionType the action type, sent by the client
		 * @return boolean true on success or false on failure
		 */
		function messageList($store, $entryid, $action, $actionType)
		{
			$searchPerformed = false;				// flag to check the request is for search or not
			$disableFullContactlist = false;		// flag for disabling the contact list

			if(!$entryid) {
				$rootcontainer = mapi_msgstore_openentry($store);
				if($rootcontainer) {
					$props = mapi_getprops($rootcontainer, array(PR_IPM_CONTACT_ENTRYID));
					
					if(isset($props[PR_IPM_CONTACT_ENTRYID])) {
						$entryid = $props[PR_IPM_CONTACT_ENTRYID];
					}
				}
			}

			if($store && $entryid) {
				$restriction = array(RES_AND, // get contacts when having one or more email adress
									array(
										array(RES_PROPERTY,
											array(	RELOP=>RELOP_EQ,
													ULPROPTAG=>PR_MESSAGE_CLASS,
													VALUE => array(PR_MESSAGE_CLASS=>"IPM.Contact")
											)
										),
										array(RES_PROPERTY,
											array(	RELOP => RELOP_GT,
													ULPROPTAG => $this->properties["address_book_long"],
													VALUE => array($this->properties["address_book_long"] => 0)
											)
										)
									)
								);

				// include distribution lists when requested
				if (!isset($action["restriction"]["hide_distlist"]) || $action["restriction"]["hide_distlist"] !== true) {
					$restriction = 	array(RES_OR,
										array(
											array(RES_PROPERTY, // get distribution lists
												array(
													RELOP => RELOP_EQ,
													ULPROPTAG => PR_MESSAGE_CLASS,
													VALUE => array( PR_MESSAGE_CLASS => "IPM.DistList" )
												)
											),
											$restriction
										)
									);
				}

				if(isset($action["restriction"])) {
					if(isset($action["restriction"]["searchstring"])) {
						$searchPerformed = true;
						$restrictions = array();
						$props = array($this->properties["fileas"], 
									   $this->properties["display_name"],
									   $this->properties["email_address_1"],
									   $this->properties["email_address_display_name_1"],
									   $this->properties["email_address_2"],
									   $this->properties["email_address_display_name_2"],
									   $this->properties["email_address_3"],
									   $this->properties["email_address_display_name_3"]);
						
						foreach($props as $property)
						{
							array_push($restrictions, array(RES_CONTENT,
															array(FUZZYLEVEL => FL_SUBSTRING|FL_IGNORECASE,
																ULPROPTAG => $property,
																VALUE => $action["restriction"]["searchstring"])));
						}

						$restrictions = array(RES_OR, $restrictions);
						$restriction = array(RES_AND, array($restriction, $restrictions));
					} else if (isset($action["restriction"]["pagination_character"]) && $action["restriction"]["pagination_character"] != "...") {
						// If request is for gab pagination then set pagination restriction.
						$searchPerformed = true;

						// Get pagination restriction and add it in restriction array.
						$paginationRestriction = $this->getPaginationRestriction($action, $actionType);
						if($paginationRestriction)
							$restriction = array(RES_AND, array($restriction, $paginationRestriction));
 					}
				}
				
				// We map the 'email_address' column to 'email_address_1' for sorting. This is a bit of a hack
				// because we are showing either email_address_1 or _2 or _3 ...
				
				$map = array();
				$map["email_address"] = $this->properties["email_address_1"];
				
				$this->parseSortOrder($action, $map, true);

				$data = array();

				// open contacts folder
				$folder = mapi_msgstore_openentry($store, $entryid);
				if(mapi_last_hresult() == NOERROR) {
					$contentsTable = mapi_folder_getcontentstable($folder, MAPI_DEFERRED_ERRORS);

					/**
					 * Check whether we have to disable the full contactlist listing using the config: 
					 * DISABLE_FULL_CONTACTLIST_THRESHOLD. we are checking here if in case 
					 * mapi_table_getrowcount returns number greater then this config value then we
					 * don't have to do any processing, so it will lessen processing time
					 */
					if(DISABLE_FULL_CONTACTLIST_THRESHOLD != -1 && !$searchPerformed) {
						if(DISABLE_FULL_CONTACTLIST_THRESHOLD >= 0 && mapi_table_getrowcount($contentsTable) > DISABLE_FULL_CONTACTLIST_THRESHOLD) {
							$disableFullContactlist = true;
						}
					}

					// apply restriction & sorting
					mapi_table_restrict($contentsTable, $restriction, TBL_BATCH);
					mapi_table_sort($contentsTable, $this->sort, TBL_BATCH);

					if(!$disableFullContactlist) {
						// Get all rows
						/**
						 * we can also use mapi_table_queryallrows but it internally calls queryrows with 
						 * start as 0 and end as 0x7fffffff, so we are directly calling mapi_table_queryrows
						 */
						$rows = mapi_table_queryrows($contentsTable, $this->properties, 0, 0x7fffffff);

						// Search for distribution lists and get all email adresses in the distribution lists.
						$items = array();
						foreach($rows as $row)
						{
							$item = Conversion::mapMAPI2XML($this->properties, $row);

							if(isset($item["props"]["message_class"])) {
								switch($item["props"]["message_class"])
								{
									case "IPM.Contact":
										if(isset($item["props"]["address_book_mv"]) && is_array($item["props"]["address_book_mv"])){
											$email_addresses = $item["props"]["address_book_mv"];
											$entryid = $item["entryid"];

											foreach($email_addresses as $email_address)
											{
												$email_address += 1; // address_book_mv starts with 0, so we add '1' here

												if(isset($item["props"]["email_address_" . $email_address])) {
													$item["props"]["email_address"] = $item["props"]["email_address_" . $email_address];
													$item["props"]["display_name"] = $item["props"]["email_address_display_name_" . $email_address];
													$item["props"]["address_type"] = $item["props"]["email_address_type_" . $email_address];
													$item["props"]["email_index"] = $email_address;

													array_push($items, $item);
												}
											}
										}
										break;
									case "IPM.DistList":
										$item["props"]["email_address"] = $item["props"]["display_name"];
										$item["props"]["address_type"] = "ZARAFA";

										$entryid = hex2bin($item["entryid"]); // need real entryid here
										$item["members"] = array("item" => $GLOBALS["operations"]->getMembersFromDistributionList($store, $entryid, $this->properties));

										// remove non-client props that has been expanded using above code
										unset($item["props"]["members"]);
										unset($item["props"]["oneoff_members"]);

										array_push($items, $item);
										break;
								}
							}
						}

						/**
						 * Check whether we have to disable the full contactlist listing using the config: 
						 * DISABLE_FULL_CONTACTLIST_THRESHOLD. We check this after we have looped through all the
						 * items (code above) becuase it could happen then after expanding the groups the number
						 * of rows crosses the limit. This is because we need to know how many rows the contactlist
						 * will contain. Also note that when the user conducts a search the list should be displayed 
						 * regardless of the number of items returned.
						 */
						if(DISABLE_FULL_CONTACTLIST_THRESHOLD != -1 && !$searchPerformed){
							if(DISABLE_FULL_CONTACTLIST_THRESHOLD >= 0 && count($items) > DISABLE_FULL_CONTACTLIST_THRESHOLD){
								$disableFullContactlist = true;
							}
						}
					}

					if(!$disableFullContactlist){
						$data = array_merge($data, array("item" => $items));
					}else{
						// Provide clue that full contactlist is disabled.
						$data = array_merge($data, array("disable_full_gab" => true));
					}

					$this->addActionData("list", $data);
					$GLOBALS["bus"]->addData($this->getResponseData());
				}
			}
		}
		
		/**
		 * Function which retrieves the list of system users in Zarafa.
		 * @param object $store MAPI Message Store Object
		 * @param array $action the action data, sent by the client
		 * @param string $actionType the action type, sent by the client
		 * @return boolean true on success or false on failure		 		 
		 */
		function GABUsers($action, $actionType)
		{
			$searchstring = "";
			$paginationCharacter = "";
			$hide_users = false;
			$hide_groups = false;
			$hide_companies = false;
			if(isset($action["restriction"])) {
				if(isset($action["restriction"]["searchstring"])) {
					// Get search string for searching in AB.
					$searchstring = $action["restriction"]["searchstring"];
				} else if (isset($action["restriction"]["pagination_character"])) {
					// Get pagination character for AB.
					$paginationCharacter = $action["restriction"]["pagination_character"];
				}

				if(isset($action["restriction"]["hide_users"])) {
					$hide_users = $action["restriction"]["hide_users"];
				}
				if(isset($action["restriction"]["hide_groups"])) {
					$hide_groups = $action["restriction"]["hide_groups"];
				}
				if(isset($action["restriction"]["hide_companies"])) {
					$hide_companies = $action["restriction"]["hide_companies"];
				}
			}

			$items = array();

			$data["page"] = array();
			$data["page"]["start"] = 0;
			$data["page"]["rowcount"] = 0;
			$data["page"]["totalrowcount"] = 0;

			$data = array();

			$this->sort = array();

			$map = array();
			$map["fileas"] = $this->ab_properties['account'];

			// Parse incoming sort order
			$this->parseSortOrder($action, $map, true, $this->ab_properties);

			if($paginationCharacter == "...")
				$paginationCharacter = "";

			if(!DISABLE_FULL_GAB || !empty($searchstring) || !empty($paginationCharacter)) {
				$ab = $GLOBALS["mapisession"]->getAddressbook();

				if (isset($action["entryid"]) && $action["entryid"] != "") {
					$entryid = hex2bin($action["entryid"]);
				}else{
					$entryid = mapi_ab_getdefaultdir($ab);
				}

				$dir = mapi_ab_openentry($ab,$entryid);
				if (mapi_last_hresult()){
					return false;
				}

				/**
				 * @TODO: "All Address Lists" on IABContainer gives MAPI_E_INVALID_PARAMETER,
				 * as it contains subfolders only. When #7344 is fixed, MAPI will return error here,
				 * handle it here and return false.
				 */
				$table = mapi_folder_getcontentstable($dir, MAPI_DEFERRED_ERRORS);

				$restriction = false;
				$tempRestriction = false;
				$userGroupRestriction = false;

				if($hide_users || $hide_groups || $hide_companies) {
					$userRestrictions = array();
					if ($hide_users) {
						$tmp = $this->createUsersRestriction($hide_users);
						if ($tmp) {
							$userRestrictions[] = $tmp;
						}
					}
					if ($hide_groups) {
						$tmp = $this->createGroupsRestriction($hide_groups);
						if ($tmp) {
							$userRestrictions[] = $tmp;
						}
					}
					if ($hide_companies) {
						$tmp = $this->createCompanyRestriction($hide_companies);
						if ($tmp) {
							$userRestrictions[] = $tmp;
						}
					}
					$userGroupRestriction = Array(RES_AND, $userRestrictions);
				}

				if(!empty($searchstring)){
					// create restriction for search
					// only return users from who the displayName or the username starts with $searchstring
					// TODO: use PR_ANR for this restriction instead of PR_DISPLAY_NAME and PR_ACCOUNT
					$tempRestriction = 	array(RES_OR, 
										array(
											array(
												RES_CONTENT,
													array(FUZZYLEVEL => FL_SUBSTRING|FL_IGNORECASE,
														ULPROPTAG => PR_DISPLAY_NAME,
														VALUE => $searchstring
													)
												),
											array(
												RES_CONTENT,
													array(FUZZYLEVEL => FL_SUBSTRING|FL_IGNORECASE,
														ULPROPTAG => PR_ACCOUNT,
														VALUE => $searchstring
													)
												),
										),
									);
				} else if(!empty($paginationCharacter)) {
					// create restriction for alphabet bar
					$tempRestriction = $this->getPaginationRestriction($action, $actionType);
 				}

				if($tempRestriction && $userGroupRestriction) {
					$restriction = Array(
										RES_AND,
											Array(
												$tempRestriction,				// restriction for search/alphabet bar
												$userGroupRestriction			// restriction for hiding users/groups
											)
									);
				} else if($tempRestriction) {
					$restriction = $tempRestriction;							// restriction for search/alphabet bar
				} else {
					$restriction = $userGroupRestriction;						// restriction for hiding users/groups
				}

				// Only add restriction when it is used
				if($restriction) {
					mapi_table_restrict($table, $restriction, TBL_BATCH);
				}
				mapi_table_sort($table, $this->sort, TBL_BATCH);

				// todo: fix paging stuff

				$data["page"]["start"] = 0;
				$data["page"]["rowcount"] = mapi_table_getrowcount($table);
				$data["page"]["totalrowcount"] = $data["page"]["rowcount"];

				$rows = mapi_table_queryrows($table, $this->ab_properties, 0, 0x7fffffff);

				for ($i = 0, $len = count($rows); $i < $len; $i++) {
                    $user_data = $rows[$i];
                    $item = array();
                    $item["entryid"] = bin2hex($user_data[$this->ab_properties["entryid"]]);
                    $item["display_name"] = $user_data[$this->ab_properties["display_name"]];
                    $item["fileas"] = $user_data[$this->ab_properties["account"]];
                    $item["object_type"] = $user_data[$this->ab_properties["object_type"]];

					switch($user_data[PR_DISPLAY_TYPE]){
                        case DT_ORGANIZATION:
							$item["display_type"] = $user_data[PR_DISPLAY_TYPE];
							$item["display_type_ex"] = $user_data[PR_DISPLAY_TYPE_EX];
                            $item["email_address"] = $user_data[$this->ab_properties["account"]];
                            $item["message_flags"] = 0; // FIXME: we want companies to show "bold", so in fact this is some kind of a hack ;)
							$item["address_type"] = "ZARAFA";
							$item["search_key"] = bin2hex($user_data[$this->ab_properties["search_key"]]);
                            break;

                        case DT_DISTLIST:
							$item["display_type"] = $user_data[PR_DISPLAY_TYPE];
							$item["display_type_ex"] = $user_data[PR_DISPLAY_TYPE_EX];
							$item["email_address"] = $user_data[$this->ab_properties["account"]];
							$item["smtp_address"] = isset($user_data[$this->ab_properties["smtp_address"]]) ? $user_data[$this->ab_properties["smtp_address"]] : "";
							$item["message_flags"] = 0; // FIXME: we want dist lists to show "bold", so in fact this is some kind of a hack ;)
							$item["address_type"] = "ZARAFA";
							$item["search_key"] = bin2hex($user_data[$this->ab_properties["search_key"]]);
							break;

                        case DT_MAILUSER:
                        default:
							$item["display_type"] = $user_data[PR_DISPLAY_TYPE];
							$item["display_type_ex"] = $user_data[PR_DISPLAY_TYPE_EX];
							$item["email_address"] = $user_data[$this->ab_properties["email_address"]];
							$item["smtp_address"] = $user_data[$this->ab_properties["smtp_address"]];
							$item["search_key"] = bin2hex($user_data[$this->ab_properties["search_key"]]);
							$item["address_type"] = isset($user_data[$this->ab_properties["address_type"]]) ? $user_data[$this->ab_properties["address_type"]] : "SMTP";
							$item["message_flags"] = MSGFLAG_READ;	// FIXME: setting message_flags to read, to fix the view
							$item["department_name"] = isset($user_data[$this->ab_properties["department_name"]]) ? $user_data[$this->ab_properties["department_name"]] : "";
							$item["office_telephone_number"] = isset($user_data[$this->ab_properties["office_telephone_number"]]) ? $user_data[$this->ab_properties["office_telephone_number"]] : "";
							$item["office_location"] = isset($user_data[$this->ab_properties["office_location"]]) ? $user_data[$this->ab_properties["office_location"]] : "";
							$item["primary_fax_number"] = isset($user_data[$this->ab_properties["primary_fax_number"]]) ? $user_data[$this->ab_properties["primary_fax_number"]] : "";
							$item["search_key"] = bin2hex($user_data[$this->ab_properties["search_key"]]);

							// Contacts from the GAL have email-address saved in smtp_address property.
							if(trim($item["email_address"]) == "") {
								$item["email_address"] = $item["smtp_address"];
							}
                            break;
                    }

                    array_push($items, array("props" => $item));
                    
                }
            } else {
	           	// Provide clue that full GAB is disabled.
            	$data = array_merge($data, array("disable_full_gab" => DISABLE_FULL_GAB));
            }
			$data = array_merge($data, array("item"=>$items));

			$this->addActionData("list", $data);
			$GLOBALS["bus"]->addData($this->getResponseData());

			return true;
		}

		/**
		 *	Function will create a restriction based on parameters passed for hiding users
		 *	@param		Array				$hide_users		list of users that should not be shown
		 *	@return		restrictionObject					restriction for hiding provided users
		 */
		function createUsersRestriction($hide_users) {
			$usersRestriction = null;

			// When $hide_users is true, then we globally disable
			// all users regardless of their subtype. Otherwise if
			// $hide_users is set then we start looking which subtype
			// is being filtered out.
			if ($hide_users === true) {
				$usersRestriction = Array(
										RES_AND,
											Array(
												Array(
													RES_PROPERTY,
														Array(
															RELOP => RELOP_NE,
															ULPROPTAG => PR_DISPLAY_TYPE,
															VALUE => Array(
																PR_DISPLAY_TYPE => DT_MAILUSER
															)
														)
												),
												Array(
													RES_PROPERTY,
														Array(
															RELOP => RELOP_NE,
															ULPROPTAG => PR_DISPLAY_TYPE,
															VALUE => Array(
																PR_DISPLAY_TYPE => DT_REMOTE_MAILUSER
															)
														)
												)
											)
									);
			} else if ($hide_users) {
				$tempRestrictions = Array();

				// wrap parameters in an array
				if(!is_array($hide_users)) {
					$hide_users = Array($hide_users);
				}

				if(in_array("non_security", $hide_users)) {
					array_push($tempRestrictions, Array(
													RES_BITMASK,
														Array(
															ULTYPE => BMR_EQZ,
															ULPROPTAG => PR_DISPLAY_TYPE_EX,
															ULMASK => DTE_FLAG_ACL_CAPABLE 
														)
													)
							);
				}

				if(in_array("room", $hide_users)) {
					array_push($tempRestrictions, Array(
													RES_PROPERTY,
														Array(
															RELOP => RELOP_EQ,
															ULPROPTAG => PR_DISPLAY_TYPE_EX,
															VALUE => Array(
																PR_DISPLAY_TYPE_EX => DT_ROOM
															)
														)
													)
							);
				}

				if(in_array("equipment", $hide_users)) {
					array_push($tempRestrictions, Array(
													RES_PROPERTY,
														Array(
															RELOP => RELOP_EQ,
															ULPROPTAG => PR_DISPLAY_TYPE_EX,
															VALUE => Array(
																PR_DISPLAY_TYPE_EX => DT_EQUIPMENT
															)
														)
													)
							);
				}

				if(in_array("active", $hide_users)) {
					array_push($tempRestrictions, Array(
													RES_PROPERTY,
														Array(
															RELOP => RELOP_EQ,
															ULPROPTAG => PR_DISPLAY_TYPE_EX,
															VALUE => Array(
																PR_DISPLAY_TYPE_EX => DTE_FLAG_ACL_CAPABLE
															)
														)
													)
							);
				}

				if(in_array("non_active", $hide_users)) {
					array_push($tempRestrictions, Array(
													RES_PROPERTY,
														Array(
															RELOP => RELOP_EQ,
															ULPROPTAG => PR_DISPLAY_TYPE_EX,
															VALUE => Array(
																PR_DISPLAY_TYPE_EX => DT_MAILUSER
															)
														)
													)
							);
				}

				if(in_array("contact", $hide_users)) {
					array_push($tempRestrictions, Array(
													RES_PROPERTY,
														Array(
															RELOP => RELOP_EQ,
															ULPROPTAG => PR_DISPLAY_TYPE_EX,
															VALUE => Array(
																PR_DISPLAY_TYPE_EX => DT_REMOTE_MAILUSER
															)
														)
													)
							);
				}

				if(in_array("system", $hide_users)) {
					array_push($tempRestrictions, Array(
													RES_CONTENT,
														Array(
															FUZZYLEVEL => FL_FULLSTRING,
															ULPROPTAG => PR_ACCOUNT,
															VALUE => Array(
																PR_ACCOUNT => "SYSTEM"
															)
														)
												)
							);
				}

				if(!empty($tempRestrictions)) {
					$usersRestriction = Array(
											RES_NOT,
											Array(
												Array(
													RES_AND,
														Array(
															Array(
																RES_OR,
																	Array(
																		Array(
																			RES_PROPERTY,
																				Array(
																					RELOP => RELOP_EQ,
																					ULPROPTAG => PR_DISPLAY_TYPE,
																					VALUE => Array(
																						PR_DISPLAY_TYPE => DT_MAILUSER
																					)
																				)
																		),
																		Array(
																			RES_PROPERTY,
																				Array(
																					RELOP => RELOP_EQ,
																					ULPROPTAG => PR_DISPLAY_TYPE,
																					VALUE => Array(
																						PR_DISPLAY_TYPE => DT_REMOTE_MAILUSER
																					)
																				)
																		)
																	)
															),
															Array(
																RES_OR,
																$tempRestrictions					// all user restrictions
															)
														)
												)
											)
										);
				}
			}

			return $usersRestriction;
		}

		/**
		 *	Function will create a restriction based on parameters passed for hiding groups
		 *	@param		Array				$hide_groups	list of groups that should not be shown
		 *	@return		restrictionObject					restriction for hiding provided users
		 */
		function createGroupsRestriction($hide_groups) {
			$groupsRestriction = null;

			// When $hide_groups is true, then we globally disable
			// all groups regardless of their subtype. Otherwise if
			// $hide_groups is set then we start looking which subtype
			// is being filtered out.
			if ($hide_groups === true) {
				$groupsRestriction = Array(
										RES_AND,
											Array(
												Array(
													RES_PROPERTY,
														Array(
															RELOP => RELOP_NE,
															ULPROPTAG => PR_DISPLAY_TYPE,
															VALUE => Array(
																PR_DISPLAY_TYPE => DT_DISTLIST
															)
														)
													)
											)
									);
			} else if($hide_groups) {
				$tempRestrictions = Array();

				// wrap parameters in an array
				if(!is_array($hide_groups)) {
					$hide_groups = Array($hide_groups);
				}

				if(in_array("non_security", $hide_groups)) {
					array_push($tempRestrictions, Array(
													RES_BITMASK,
														Array(
															ULTYPE => BMR_EQZ,
															ULPROPTAG => PR_DISPLAY_TYPE_EX,
															ULMASK => DTE_FLAG_ACL_CAPABLE 
														)
													)
							);
				}

				if(in_array("normal", $hide_groups)) {
					array_push($tempRestrictions, Array(
													RES_PROPERTY,
														Array(
															RELOP => RELOP_EQ,
															ULPROPTAG => PR_DISPLAY_TYPE_EX,
															VALUE => Array(
																PR_DISPLAY_TYPE_EX => DT_DISTLIST
															)
														)
													)
							);
				}

				if(in_array("security", $hide_groups)) {
					array_push($tempRestrictions, Array(
													RES_PROPERTY,
														Array(
															RELOP => RELOP_EQ,
															ULPROPTAG => PR_DISPLAY_TYPE_EX,
															VALUE => Array(
																PR_DISPLAY_TYPE_EX => (DT_SEC_DISTLIST | DTE_FLAG_ACL_CAPABLE)
															)
														)
													)
							);
				}

				if(in_array("dynamic", $hide_groups)) {
					array_push($tempRestrictions, Array(
													RES_PROPERTY,
														Array(
															RELOP => RELOP_EQ,
															ULPROPTAG => PR_DISPLAY_TYPE_EX,
															VALUE => Array(
																PR_DISPLAY_TYPE_EX => DT_AGENT
															)
														)
													)
							);
				}

				if(in_array("everyone", $hide_groups)) {
					array_push($tempRestrictions, Array(
													RES_CONTENT,
														Array(
															FUZZYLEVEL => FL_FULLSTRING,
															ULPROPTAG => PR_ACCOUNT,
															VALUE => Array(
																PR_ACCOUNT => "Everyone"
															)
														)
													)
							);
				}

				if(!empty($tempRestrictions)) {
					$groupsRestriction = Array(
											RES_NOT,
											Array(
												Array(
													RES_AND,
														Array(
															Array(
																RES_PROPERTY,
																	Array(
																		RELOP => RELOP_EQ,
																		ULPROPTAG => PR_DISPLAY_TYPE,
																		VALUE => Array(
																			PR_DISPLAY_TYPE => DT_DISTLIST
																		)
																	)
															),
															Array(
																RES_OR,
																$tempRestrictions					// all group restrictions
															)
														)
												)
											)
										);
				}
			}

			return $groupsRestriction;
		}

		/**
		 *	Function will create a restriction to get company information
		 *	@param		Boolean				$hide_companies	true/false
		 *	@return		restrictionObject					restriction for getting company info
		 */
		function createCompanyRestriction($hide_companies) {
			$companyRestriction = false;

			if($hide_companies) {
				$companyRestriction = Array(
											RES_PROPERTY,
												Array(
													RELOP => RELOP_NE,
													ULPROPTAG => PR_DISPLAY_TYPE,
													VALUE => Array(
															PR_DISPLAY_TYPE => DT_ORGANIZATION
													)
												)
										);
			}

			return $companyRestriction;
		}

		function getHierarchy($action)
		{
			$data = array();

			$storeslist = false;
			if (isset($action["contacts"])){
				if (isset($action["contacts"]["stores"]["store"]) && !is_array($action["contacts"]["stores"]["store"])){
					$action["contacts"]["stores"]["store"] = array($action["contacts"]["stores"]["store"]);
				}
				if (isset($action["contacts"]["stores"]["folder"]) && !is_array($action["contacts"]["stores"]["folder"])){
					$action["contacts"]["stores"]["folder"] = array($action["contacts"]["stores"]["folder"]);
				}
				$storeslist = $action["contacts"]["stores"];
			}
			
			$folders = $GLOBALS["operations"]->getAddressbookHierarchy($storeslist);

			$data = array( "item" => $folders );

			$this->addActionData("list", $data);
			$GLOBALS["bus"]->addData($this->getResponseData());

			return true;
		}


		function expandGroup($entryid)
		{
			$result = array();
			$group = mapi_ab_openentry($GLOBALS["mapisession"]->getAddressbook(), $entryid);
			$table = mapi_folder_getcontentstable($group, MAPI_DEFERRED_ERRORS);
			$items = mapi_table_queryallrows($table, $this->ab_properties);
			foreach($items as $item){
				if($item[$this->ab_properties["display_type"]] == DT_MAILUSER && isset($item[$this->ab_properties["smtp_address"]])) {
					$result[] = array(
							"entryid"=>bin2hex($item[$this->ab_properties["entryid"]]),
							"fileas"=>$item[$this->ab_properties["account"]],
							"display_name"=>$item[$this->ab_properties["display_name"]],
							"address_type"=>$item[$this->ab_properties["address_type"]],
							"email_address"=>$item[$this->ab_properties["smtp_address"]],
						);
				}
			}
			return $result;
		}

		/**
		 * Function will return restriction used in GAB pagination.
		 * @param array $action the action data, sent by the client
		 * @param string $actionType the action type, sent by the client
		 * @return array paginationRestriction returns restriction used in pagination.
		 */
		function getPaginationRestriction($action, $actionType)
		{
			if(isset($action["restriction"]["pagination_character"])) {
				// Get sorting column to provide pagination on it.
				if(isset($action["sort"]) && isset($action["sort"]["column"]))
					$sortColumn = $action["sort"]["column"][0]["_content"];

				$paginationColumnProperties = array();
				// Get Pagination column Properties.
				if($actionType == "contacts") {
					array_push($paginationColumnProperties, $this->properties["fileas"]);
					array_push($paginationColumnProperties, $this->properties["display_name"]);
					array_push($paginationColumnProperties, $this->properties["email_address_1"]);
					array_push($paginationColumnProperties, $this->properties["email_address_display_name_1"]);
					array_push($paginationColumnProperties, $this->properties["email_address_2"]);
					array_push($paginationColumnProperties, $this->properties["email_address_display_name_2"]);
					array_push($paginationColumnProperties, $this->properties["email_address_3"]);
					array_push($paginationColumnProperties, $this->properties["email_address_display_name_3"]);
				} else if ($actionType == "globaladdressbook") {
					array_push($paginationColumnProperties, $this->ab_properties["account"]);
					array_push($paginationColumnProperties, $this->ab_properties["display_name"]);
					array_push($paginationColumnProperties, $this->ab_properties["smtp_address"]);
					array_push($paginationColumnProperties, $this->ab_properties["department_name"]);
					array_push($paginationColumnProperties, $this->ab_properties["office_location"]);
				}

				// Get Pagination character.
				$paginationCharacter = $action["restriction"]["pagination_character"];
				
				// Create restriction according to paginationColumn
				$restrictions = array();
				foreach ($paginationColumnProperties as $paginationColumnProperty)
				{
					switch ($paginationCharacter){
						case "123":
							array_push($restrictions,
												array(
														RES_AND,
														array(
															array(
																RES_PROPERTY,
																array(
																	RELOP => RELOP_GE,
																	ULPROPTAG =>  $paginationColumnProperty,
																	VALUE => array(
																		$paginationColumnProperty => "0"
																	)
																)
															),
															array(
																RES_PROPERTY,
																array(
																	RELOP => RELOP_LE,
																	ULPROPTAG => $paginationColumnProperty,
																	VALUE => array(
																		$paginationColumnProperty => "9"
																	)
																)
															)
														)
													)
												);
						break;

						case "z":
							array_push($restrictions,
											array(
												RES_PROPERTY,
												array(RELOP => RELOP_GE,
													ULPROPTAG => $paginationColumnProperty,
													VALUE => array(
														$paginationColumnProperty => "z" 
														)
													)
												)
											);
						break;

						default:
							array_push($restrictions,
													array(
															RES_AND,
															array(
																array(
																	RES_PROPERTY,
																	array(
																		RELOP => RELOP_GE,
																		ULPROPTAG =>  $paginationColumnProperty,
																		VALUE => array(
																			$paginationColumnProperty => $paginationCharacter
																		)
																	)
																),
																array(
																	RES_PROPERTY,
																	array(
																		RELOP => RELOP_LT,
																		ULPROPTAG => $paginationColumnProperty,
																		VALUE => array(
																			$paginationColumnProperty => chr(ord($paginationCharacter) + 1)
																		)
																	)
																)
															)
														)
													);
					}
				}
				$paginationRestriction = array(RES_OR, $restrictions);
			}

			if($paginationRestriction)
				return $paginationRestriction;
			else
				return false;
		}
	}

?>
