View file wapirate/wml/phpcls/libgmailer.php

File size: 148.63Kb
<?php

/**

 * Include (require) this page if your application wish to use the class Gmailer.

 * This page (libgmailer.php) is the definition of 3 classes: GMailer, GMailSnapshot

 * and Debugger (deprecated).

 *

 * @package libgmailer.php

 */

 

/**

 * Constant defined by application author. Set it to true if the class is used as

 * a module of an online office app or other situation where PHP Session should NOT

 * by destroyed after signing out from Gmail.

 *

 * @var bool

 */

define("GM_USE_LIB_AS_MODULE",		false);	// Normal operation



/**#@+ 

 * URL's of Gmail.

 * @var string 

 */

define("GM_LNK_GMAIL",        		"https://mail.google.com/mail/");

define("GM_LNK_GMAIL_HTTP",        	"http://mail.google.com/mail/");

// Changed by Gan; 10 Sept 2005

define("GM_LNK_LOGIN",				"https://www.google.com/accounts/ServiceLoginAuth");

// Added by Neerav; 4 Apr 2006

define("GM_LNK_LOGIN_REFER",				"https://www.google.com/accounts/ServiceLogin?service=mail&passive=true&rm=false&continue=http%3A%2F%2Fmail.google.com%2Fmail%3Fui%3Dhtml%26zy%3Dl&ltmpl=yj_blanco&ltmplcache=2&hl=en");

// Added by Neerav; 5 June 2005

define("GM_LNK_INVITE_REFER",	 	"https://www.google.com/accounts/ServiceLoginBox?service=mail&continue=https%3A%2F%2Fmail.google.com%2Fmail");

// Updated by Neerav; 5 Mar 2006

define("GM_USER_AGENT", "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.10) Gecko/20050716 Firefox/1.0.6");



/**

 * @deprecated

 */

define("GM_LNK_LOGOUT",				"https://mail.google.com/mail/?logout");

define("GM_LNK_REFER",				"https://www.google.com/accounts/ServiceLoginBox?service=mail&continue=https%3A%2F%2Fmail.google.com%2Fmail");

define("GM_LNK_CONTACT",			"https://mail.google.com/mail/?view=cl&search=contacts&pnl=a");

define("GM_LNK_ATTACHMENT",			"https://mail.google.com/mail/?view=att&disp=att");

define("GM_LNK_ATTACHMENT_ZIPPED",	"https://mail.google.com/mail/?view=att&disp=zip");

/**#@-*/



/**#@+ 

 * Constants defining Gmail content's type.

 * @var int 

*/

define("GM_STANDARD",			0x001);

define("GM_LABEL",				0x002);

define("GM_CONVERSATION",		0x004);

define("GM_QUERY",				0x008);

define("GM_CONTACT",			0x010);

define("GM_PREFERENCE",			0x020);

/**#@-*/



/**#@+ 

 * Constants defining Gmail action.

 * @var int 

*/

/**

 * Apply label to conversation

*/

define("GM_ACT_APPLYLABEL",		1);

/**

 * Remove label from conversation

*/

define("GM_ACT_REMOVELABEL",	2);

/**

 * Star a conversation

*/

define("GM_ACT_STAR",			3);

/**

 * Remove a star from (unstar) a conversation

*/

define("GM_ACT_UNSTAR",			4);

/**

 * Mark a conversation as spam

*/

define("GM_ACT_SPAM",			5);

/**

 * Unmark a conversation from spam

*/

define("GM_ACT_UNSPAM",			6);

/**

 * Mark conversation as read

*/

define("GM_ACT_READ",			7);

/**

 * Mark conversation as unread

*/

define("GM_ACT_UNREAD",			8);

/**

 * Trash a conversation

*/

define("GM_ACT_TRASH",			9);

/**

 * Directly delete a conversation

*/

define("GM_ACT_DELFOREVER",		10);

/**

 * Archive a conversation

*/

define("GM_ACT_ARCHIVE",		11);

/**

 * Move conversation to Inbox

*/

define("GM_ACT_INBOX",			12);

/**

 * Move conversation out of Trash

*/

define("GM_ACT_UNTRASH",		13);

/**

 * Discard a draft

*/

define("GM_ACT_UNDRAFT",		14);

/**

 * Trash individual message.

*/ 

define("GM_ACT_TRASHMSG",		15);		

/**

 * Untrash (retrieve from trash) individual message.

 * @since 27 Feb 2006

*/ 

define("GM_ACT_UNTRASHMSG",		18);		

/**

 * Delete spam, forever.

*/ 

define("GM_ACT_DELSPAM",		16);

/**

 * Delete trash message, forever.

*/ 

define("GM_ACT_DELTRASHED",		17);

/**

 * Deleted trashed messages from the thread forever.

 * @since 27 Feb 2006

*/ 

define("GM_ACT_DELTRASHEDMSGS",	19);

/**#@-*/



/**#@+ 

 * Other constants.

*/

define("GM_VER", "0.9 Beta 2");

define("GM_COOKIE_KEY",			"LIBGMAILER");

define("GM_COOKIE_IK_KEY",		"LIBGMAILER_IdKey");	// Added by Neerav; 6 July 2005

define("GM_USE_COOKIE",			0x001);

define("GM_USE_PHPSESSION",   	0x002);

/**#@-*/





/**

 * Class GMailer is the main class/library for interacting with Gmail (Google's

 * free webmail service) with ease.

 * 

 * <b>Acknowledgement</b><br/>It is not completely built from scratch. It is based on: "Gmail RSS feed in PHP"

 * by thimal, "Gmail as an online backup system" by Ilia Alshanetsky, and "Gmail

 * Agent API" by Johnvey Hwang and Eric Larson. 

 *

 * Special thanks to Eric Larson and all other users, testers, and forum posters

 * for their bug reports, comments and advices.

 *

 * @package GMailer

 * @author Gan Ying Hung <ganyinghung|no@spam|users.sourceforge.net>

 * @author Neerav Modi <neeravmodi|no@spam|users.sourceforge.net>

 * @link http://gmail-lite.sourceforge.net Project homepage

 * @link http://sourceforge.net/projects/gmail-lite Sourceforge project page

 * @version 0.8.0-rc

*/

class GMailer {

   /**#@+

    * @access private

    * @var string

   */

	var $cookie_str;

	var $login;

	var $pwd;

	/**

	 * @author Neerav

	 * @since 13 Aug 2005

	*/

	var $gmail_data;

	/**

	 * Raw packet

	*/

	var $raw;

	/**

	 * Raw packet for contact list

	*/

	var $contact_raw;

	var $timezone;

	var $use_session;

	var $proxy_host;

	var $proxy_auth;	

	/**#@-*/	 

	

	/**

	 * Reserved mailbox names

	*/

	var $gmail_reserved_names = array("inbox", "star", "starred", "chat", "chats", "draft", "drafts", 

			"sent", "sentmail", "sent-mail", "sent mail", "all", "allmail", "all-mail", "all mail",

			"anywhere", "archive", "spam", "trash", "read", "unread");

	

	/**

	 * @access public

	 * @var bool

	*/

   var $created;

   /**

	 * Status of GMailer

	 *

	 * If something is wrong, check this class property to see what is

	 * going wrong.

	 *

	 * @author Neerav

	 * @since 8 July 2005

	 * @var mixed[]

	 * @access public

	*/

	var $return_status = array();



	

	/**

	 * Constructor of GMailer

	 *

	 * During the creation of GMailer object, it will perform several tests to see

	 * if the cURL extension is available or not. However, 

	 * note that the constructor will NOT return false or null even if these tests

	 * are failed. You will have to check the class property {@link GMailer::$created} to see if

	 * the object "created" is really, uh, created (i.e. working), and property

	 * {@link GMailer::$return_status} or method {@link GMailer::lastActionStatus()} to see what was going wrong.

	 *

	 * Example:

	 * <code>

	 * <?php

	 *    $gmailer = new GMailer();

	 *    if (!$gmailer->created) {

	 *       echo "Error message: ".$gmailer->lastActionStatus("message");

	 *    } else {

	 *       // Do something with $gmailer

	 *    }

	 * ? >

	 * </code>

	 *

    * A typical usage of GMailer object would be like this:

    * <code>

    * <?php

    *    require_once("libgmailer.php");

    *

    *    $gmailer = new GMailer();

    *    if ($gmailer->created) {

    *       $gmailer->setLoginInfo($gmail_acc, $gmail_pwd, $my_timezone);

    *       $gmailer->setProxy("proxy.company.com");

    *       if ($gmailer->connect()) {

    *          // GMailer connected to Gmail successfully.

    *          // Do something with it.

    *       } else {

    *          die("Fail to connect because: ".$gmailer->lastActionStatus());

    *       }

    *    } else {

    *       die("Failed to create GMailer because: ".$gmailer->lastActionStatus());

    *    }

    * ? >

    * </code>	 

	 *

	 * @see GMailer::$created, GMailer::$return_status, GMailer::lastActionStatus()

	 * @return GMailer

	*/

	function GMailer() {

		// GMailer needs "curl" extension to work

		$this->created = true;

		if (!extension_loaded('curl')) {

			// Added to gracefully handle multithreaded servers; by Neerav; 8 July 2005

			if (isset($_ENV["NUMBER_OF_PROCESSORS"]) and ($_ENV["NUMBER_OF_PROCESSORS"] > 1)) {

				$this->created = false;

				$a = array(

					"action" 		=> "constructing GMailer object",

					"status" 		=> "failed",

					"message" 		=> "libgmailer: Using a multithread server. Ensure php_curl.dll has been enabled (uncommented) in your php.ini."

				);

				array_unshift($this->return_status, $a);



			} else {

				if (!dl('php_curl.dll') && !dl('curl.so')) {

					$this->created = false;

					$a = array(

						"action" 		=> "constructing GMailer object",

						"status" 		=> "failed",

						"message" 		=> "libgmailer: unable to load curl extension."

					);

					array_unshift($this->return_status, $a);

				}

			}

		}

		if (!function_exists("curl_setopt")) {			  

			$this->created = false;

			$a = array(

				"action" 		=> "constructing GMailer object",

				"status" 		=> "failed",

				"message" 		=> "libgmailer: No curl."

			);

			array_unshift($this->return_status, $a);

		}

		$this->login = 0;

		$this->pwd = 0;

		$this->proxy_host = "";

		$this->proxy_auth = "";

		$this->use_session = 2;

		if ($this->created == true) {

			$a = array(

				"action" 		=> "constructing GMailer object",

				"status" 		=> "success",

				"message" 		=> "libgmailer: Constructing completed."

			);

			array_unshift($this->return_status, $a);

		}

	}

	

	/**

	* Set Gmail's login information.

	*

	* @return void

	* @param string $my_login Gmail's login name (without @gmail.com)

	* @param string $my_pwd Password

	* @param float $my_tz Timezone with respect to GMT, but in decimal. For example, -2.5 for -02:30GMT

	*/

	function setLoginInfo($my_login, $my_pwd, $my_tz) {

		$this->login = $my_login;

		$this->pwd = $my_pwd;

		$this->timezone = strval($my_tz*-60);

		// Added return_status; by Neerav; 16 July 2005

		$a = array(

			"action" 		=> "set login info",

			"status" 		=> "success",

			"message" 		=> "libgmailer: LoginInfo set."

		);

		array_unshift($this->return_status, $a);

	}

	

	/**

	* Setting proxy server.

	*

	* Example:

	* <code>

	* <?php

	*    // proxy server requiring login

	*    $gmailer->setProxy("proxy.company.com", "my_name", "my_pwd");

	* 

	*    // proxy server without login

	*    $gmailer->setProxy("proxy2.company.com", "", "");

	* ? >

	* </code>

	*	

	* @return void

	* @param string $host Proxy server's hostname

	* @param string $username User name if login is required

	* @param string $pwd Password if required

	*/

	function setProxy($host, $username, $pwd) {

		if (strlen($this->proxy_host) > 0) {

			$this->proxy_host = $host;

			if (strlen($username) > 0 || strlen($pwd) > 0) {

				$this->proxy_auth = $username.":".$pwd;

			}

			$a = array(

				"action" 		=> "set proxy",

				"status" 		=> "success",

				"message" 		=> "libgmailer: Proxy set."

			);

			array_unshift($this->return_status, $a);

		} else {

			$a = array(

				"action" 		=> "set proxy",

				"status" 		=> "failed",

				"message" 		=> "libgmailer: no hostname supplied."

			);

			array_unshift($this->return_status, $a);

		}

	}

	

	/**

	* Setting session management method.

	* 

	* You have to select a session management method so that GMailer would "remember"

	* your identity. Method has to be one of the following values:

	* 1. {@link GM_USE_COOKIE} | !{@link GM_USE_PHPSESSION} (if your server does not have PHP Session installed)

	* 2. !{@link GM_USE_COOKIE} | {@link GM_USE_PHPSESSION} (if your server have PHP Session installed, and don't want to set browser's cookie)

	* 3. {@link GM_USE_COOKIE} | {@link GM_USE_PHPSESSION} (if your server have PHP Session installed, and would like to use cookie to store session)

	*

	* @return void

	* @param int $method	

	*/

	function setSessionMethod($method) {

		if ($method & GM_USE_PHPSESSION) {

			if (!extension_loaded('session')) {

				// Added to gracefully handle multithreaded servers; by Neerav; 8 July 2005

				if (isset($_ENV["NUMBER_OF_PROCESSORS"]) and ($_ENV["NUMBER_OF_PROCESSORS"] > 1)) {

					$this->setSessionMethod(GM_USE_COOKIE | !GM_USE_PHPSESSION);  // forced to use custom cookie

					$a = array(

						"action" 		=> "load PHP session extension",

						"status" 		=> "failed",

						"message" 		=> "Using a multithread server. Ensure php_session.dll has been enabled (uncommented) in your php.ini."

					);

					array_unshift($this->return_status, $a);

					return;

				} else {

					// Changed extension loading; by Neerav; 18 Aug 2005

					//if (!dl('php_session.dll') && !dl('session.so')) {

					if (dl(((PHP_SHLIB_SUFFIX == 'dll') ? 'php_' : '') . 'session.' . PHP_SHLIB_SUFFIX)) {

						$a = array(

							"action" 		=> "load PHP session extension",

							"status" 		=> "failed",

							"message" 		=> "unable to load PHP session extension."

						);

						array_unshift($this->return_status, $a);

						$this->setSessionMethod(GM_USE_COOKIE | !GM_USE_PHPSESSION);  // forced to use custom cookie

						return;

					}

				}

			}

			if (!($method & GM_USE_COOKIE)) {

				@ini_set("session.use_cookies",	 0);

				@ini_set("session.use_trans_sid", 1);					 

				$a = array(

					"action" 		=> "session",

					"status" 		=> "success",

					"message" 		=> "no using cookie"

				);

				array_unshift($this->return_status, $a);

			} else {

				@ini_set("session.use_cookies",	 1);

				@ini_set("session.use_trans_sid", 0);

				$a = array(

					"action" 		=> "session",

					"status" 		=> "success",

					"message" 		=> "using cookie"

				);

				array_unshift($this->return_status, $a);

			}

			@ini_set("arg_separator.output", '&amp;');

			session_start();

			$a = array(

				"action" 		=> "session",

				"status" 		=> "success",

				"message" 		=> "using PHP session"

			);

			array_unshift($this->return_status, $a);

			$this->use_session = true;			  

		} else {

			//@ini_set("session.use_only_cookies", 1);

			@ini_set("session.use_cookies",	 1);

			@ini_set("session.use_trans_sid", 0);

			$a = array(

				"action" 		=> "session",

				"status" 		=> "success",

				"message" 		=> "using cookie"

			);

			array_unshift($this->return_status, $a);

			$this->use_session = false;

		}

	}			



	/**

	* @return binary image

	* @desc 

	*/

/* 	function retrieveCaptcha($login, $logintoken) { */

/* 		Debugger::say("retLogin: ".$login); */

/* 		Debugger::say("retToken: ".$logintoken); */

/* 		 */

/* 		$login = str_replace("@gmail.com",$login); */

/* 		$c = curl_init(); */

/*  */

/* 		curl_setopt($c, CURLOPT_RETURNTRANSFER, 1); */

/* 		curl_setopt($c, CURLOPT_BINARYTRANSFER, 1); */

/* 		curl_setopt($c, CURLOPT_FOLLOWLOCATION, 1); */

/* 		curl_setopt($c, CURLOPT_URL, "https://www.google.com/accounts/Captcha?ctoken=".urlencode($logintoken)."&amp;email=".$login."@gmail.com"); */

/* 		curl_setopt($c, CURLOPT_SSL_VERIFYHOST,  2); */

/* 		curl_setopt($c, CURLOPT_USERAGENT, GM_USER_AGENT); */

/* 		//	curl_setopt($c, CURLOPT_COOKIE, $this->cookie_str);				 */

/* 		$this->CURL_PROXY($c); */

/* //		curl_setopt($c, CURLOPT_HEADER, 1); */

/* 		curl_setopt($c, CURLOPT_SSL_VERIFYPEER, FALSE); */

/* 		curl_setopt($c, CURLOPT_REFERER, "https://www.google.com/accounts/ServiceLoginAuth"); */

/* 		$this->gmail_data = curl_exec($c); */

/* 		curl_close($c); */

/* 		 */

/* 		return $this->gmail_data; */

/* 		//return 1; */

/* 	} */



	/**

	* Connect to Gmail without setting any session/cookie

	*

	* @return bool Connect to Gmail successfully or not

	*/

	function connectNoCookie() {

		$postdata  = "service=mail";

		$postdata .= "&Email=".urlencode($this->login);

		$postdata .= "&Passwd=".urlencode(str_replace(' ','+',$this->pwd));

		$postdata .= "&null=Sign%20in";

		$postdata .= "&continue=https%3A%2F%2Fmail.google.com%2Fmail%3F";

		// Added by Neerav; 28 June 2005

		$postdata .= "&rm=false"; 	// not required but appears

		$postdata .= "&hl=en";

/* 		// Updated by Neerav; 4 Apr 2006 */

/* 		$postdata = array(); */

/* 		$postdata['ltempl'] 		= "yj_blanco";	 */

/* 		$postdata['ltemplcache'] 	= 2;	 */

/* 		$postdata['continue'] 		= "http://mail.google.com/mail/";	 */

/* 		$postdata['service'] 		= "mail";	 */

/* 		$postdata['rm'] 			= "false";	 */

/* 		$postdata['hl'] 			= "en";	 */

/* 		$postdata['Email'] 			= $this->login;	 */

/* 		$postdata['Passwd'] 		= str_replace(' ','+',$this->pwd);	 */

/* 		$postdata['rmShown'] 		= 1;	 */

/* 		$postdata['null'] 			= "Sign in";	 */

				

		// Added by Neerav; 8 July 2005

		// login challenge

		//id="logintoken" value="cpVIYkaTDTkVZ9ZHNM_384GVV79tjExj-ac2NFVgS3AVbm7lEn7Q967JHKe_sDzMP7plluysBDJRyUwkjuHQFw:D0cwussDwRyIgJGSdeMMnA" name="logintoken"> 

		if (isset($this->logintoken)   and $this->logintoken != "")   $postdata .= "&logintoken=".$logintoken;

		if (isset($this->logincaptcha) and $this->logincaptcha != "") $postdata .= "&logincaptcha=".$logincaptcha;



		

		$this->gmail_data = GMailer::execute_curl(GM_LNK_LOGIN, GM_LNK_LOGIN_REFER, 'post', $postdata, 'nocookie', "");

/* 		Debugger::say("first phase: ".print_r($this->gmail_data,true)); */

		$a = array(

			"action" 		=> "connecting to Gmail (without cookie)",

			"status" 		=> (($this->gmail_data != "") ? "success" : "failed"),

			"message" 		=> (($this->gmail_data != "") ? "connected to Gmail (without cookie)" : "no response"),

			"login_error" 	=> (($this->gmail_data != "") ? "" : "no response")

		);

		array_unshift($this->return_status, $a);

		if ($this->gmail_data == "") return false;



		/** from here we have to perform "cookie-handshaking"... **/		

		$cookies = GMailer::get_cookies($this->gmail_data);

/* 		Debugger::say("first phase cookies: ".print_r($cookies,true)); */

/* 		print_r($cookies); */

		

		$this->logintoken	= "";

		$this->logincaptcha	= "";



		if (strpos($this->gmail_data, "errormsg_0_Passwd") > 0) {

			$this->cookie_str = "";

			$this->cookie_ik_str = "";

			// Added appropriate error message; by Neerav; 8 July 2005

			$a = array(

				"action" 		=> "sign in",

				"status" 		=> "failed",

				"message" 		=> "Username and password do not match. (You provided ".$this->login.")",

				"login_error" 	=> "userpass"

			);

			array_unshift($this->return_status, $a);

			return false;



		// Added to support login challenge; by Neerav; 8 July 2005

		} elseif (strpos($this->gmail_data, "errormsg_0_logincaptcha") > 0) {

			$this->cookie_str = "";

			$this->cookie_ik_str = "";

			//id="logintoken" value="cpVIYkaTDTkVZ9ZHNM_384GVV79tjExj-ac2NFVgS3AVbm7lEn7Q967JHKe_sDzMP7plluysBDJRyUwkjuHQFw:D0cwussDwRyIgJGSdeMMnA" name="logintoken"> 

			ereg("id=\"logintoken\" value=\"([^\"]*)\" name=\"logintoken\"", $this->gmail_data, $matches);

			//Debugger::say("Connect FAILED: login challenge: ".$this->gmail_data);

			//Debugger::say("ErrorLogin: ".$this->login);

			//Debugger::say("ErrorToken: ".$matches[1]);

			//Debugger::say("logintoken: ".print_r($matches,true));

			// Added appropriate error message; by Neerav; 8 July 2005

			$a = array(

				"action" 		=> "sign in",

				"status" 		=> "failed",

				"message" 		=> "login challenge",

				"login_token"	=> $matches[1],

				//"login_token_img" => urlencode("Captcha?ctoken=".$matches[1]."&amp;email=".$this->login."%40gmail.com"),

				//"login_token_img" => $login_img,

				//"login_cookie" 	=> $login_cookie,

				"login_error" 	=> "challenge"

				

			);

			array_unshift($this->return_status, $a);

			return false;



		// Check if the Gmail URL has changed; Added by Neerav; 14 Sept 2005

 		} elseif (strpos($this->gmail_data, "Invalid request.")) {

			$this->cookie_str = "";

			$this->cookie_ik_str = "";

			

			$a = array(

				"action" 		=> "sign in",

				"status" 		=> "failed",

				"message" 		=> "Gmail: Invalid request. (libgmailer: Gmail seems to have changed the URL again.)",

				"login_error" 	=> "URL"

			);

			array_unshift($this->return_status, $a);

			return false;



		// Check for a cookie as a way to check the Gmail URL; Added by Neerav; 14 Sept 2005

		} elseif ($cookies == "") {

			$this->cookie_str = "";

			$this->cookie_ik_str = "";

			

			$a = array(

				"action" 		=> "sign in",

				"status" 		=> "failed",

				"message" 		=> "libgmailer: Phase one cookie not obtained. Gmail may be down.",

				"login_error" 	=> "cookie"

			);

			array_unshift($this->return_status, $a);

			return false;



		}

			

		$a = array(

			"action" 		=> "phase one cookie",

			"status" 		=> "success",

			"message" 		=> "Received: ".$cookies

		);

		array_unshift($this->return_status, $a);

		

		/*** js forward path (Gan:  no longer used? 10 Sept 2005)

		$a = strpos($this->gmail_data, "top.location = \"");

		$b = strpos($this->gmail_data, ";", $a);

		$forward = substr($this->gmail_data, $a+16, $b-($a+16)-1);



		// forces relative url into absolute if not already; Added by Neerav; 31 July 2005 

		if (substr($forward,0,8) != "https://") {

			$forward = "https://mail.google.com/accounts/".$forward;

		}

		**/

		$a = strpos($this->gmail_data, "Location: ");

		$b = strpos($this->gmail_data, "\n", $a);

		$forward = substr($this->gmail_data, $a+10, $b-($a+10));

		$a = array(

			"action" 		=> "redirecting",

			"status" 		=> "success",

			"message" 		=> "Redirecting to: ".$forward

		);

		array_unshift($this->return_status, $a);

			

		// Forward url is now absolute instead of relative; Fixed by Gan; 27 July 2005

		//curl_setopt($c, CURLOPT_URL, "https://mail.google.com/accounts/".$forward);

/* 		$ret = GMailer::execute_curl($forward, GM_LNK_REFER, 'post', $postdata, "cookie", $cookies); */

		// Added extra required cookie; by Neerav; 4 Apr 2006

		$second = GMailer::execute_curl($forward, GM_LNK_LOGIN_REFER, 'get', "", "cookie", "GoogleAccountsLocale_session=en; ".$cookies);

		

		$data = GMailer::get_cookies($second);

/* 		Debugger::say("second phase: ".print_r($second,true)); */

/* 		Debugger::say("second phase cookies: ".print_r($data,true)); */

/* 		print_r($data); */

		

		$a = array(

			"action" 		=> "phase two cookie",

			"status" 		=> "success",

			"message" 		=> "Obtained: ".$d

		);

		array_unshift($this->return_status, $a);

				 

/* 		$this->cookie_str = $cookies.";".$d;  // the cookie string obtained from gmail */



		if (strpos($second, "SetSID") !== false) {

			$a = array(

				"action" 		=> "phase three required",

				"status" 		=> "success",

				"message" 		=> "Starting..."

			);

/* 			$forward = preg_match("/<meta content=\"0;\s*url=([^\"]*)\"/",$second,$matches); */

/* 			print_r($matches); */

/* 			Debugger::say("third phase location: ".print_r($matches,true)); */

			

/* 			$third = GMailer::execute_curl( */

/* 				str_replace("&amp;","&",$forward[1]),  */

/* 				"", // no referrer  */

/* 				'get', "",  */

/* 				"nocookie", ""); */

			$forward = preg_match("/<meta content=\"0;\s*url=([^\"]*)\"/",$second,$matches);

/* 			print_r($matches); */

/* 			Debugger::say("third phase location: ".print_r($matches,true)); */

/* 			print_r(str_replace("&amp;","&",$matches[1])); */



			

			$third = GMailer::execute_curl(

				str_replace("&amp;","&",$matches[1]), 

				"", // no referrer 

				'get', "", 

				"nocookie", "");

			$data = GMailer::get_cookies($third);

/* 			Debugger::say("third phase: ".print_r($third,true)); */

/* 			Debugger::say("third phase cookies: ".print_r($data,true)); */

			$data = preg_replace("/GX=.*?;\s?GX=/","GX=",$data);

/* 			Debugger::say("third phase cookies (corrected): ".print_r($data,true)); */

			

		}



		$d = ($data) ? $data : $cookies;

		$d = $d.";TZ=".$this->timezone;

	

		$this->cookie_str = preg_replace("/LSID=mail[^;]*?;/","",$d);  // the cookie string obtained from gmail		

		

/* 		print_r($this->cookie_str); */

		// cleanup redundant cookies

/* 		$this->cookie_str = ereg_replace( */

/* 								"S=gmail=([^\:]*):gmail_yj=([^\:]*):gmproxy=([^\;]*);",  */

/* 								"",  */

/* 								$this->cookie_str */

/* 							); */

/* 		$this->cookie_str .= ";S=gmail=".$matches[1].":gmail_yj=".$matches[2].":gmproxy=".$matches[3].";"; */



		return true;

		

	}		

	

	/**

	* Connect to GMail with default session management settings.

	*

	* @return bool Connect to Gmail successfully or not

	*/

	function connect() {

		if ($this->use_session === 2)

			$this->setSessionMethod(GM_USE_COOKIE | GM_USE_PHPSESSION);	  // by default

		

		// already logged in

		if ($this->login == 0 && $this->pwd == 0) {

			if (!$this->getSessionFromBrowser()) {			  

				return $this->connectNoCookie() && $this->saveSessionToBrowser();

			} else {

				$a = array(

					"action" 		=> "connect",

					"status" 		=> "success",

					"message" 		=> "Connect completed by getting cookie/session from browser/server."

				);

				array_unshift($this->return_status, $a);

				return true;

			}



		// log in

		} else {

			// Changed to support login challenge; by Neerav; 8 July 2005 

			//return $this->connectNoCookie() && $this->saveSessionToBrowser();

			if ($this->connectNoCookie()) {

				return $this->saveSessionToBrowser();

			} else {

				return false;

			}

		}

	}

	

	/**

	* See if it is connected to GMail.

	*

	* @return bool

	*/

	function isConnected() {

		return (strlen($this->cookie_str) > 0);

	}



	/**

	* Last action's action, status, message, and other info

	*

	* @param string $request What information you would like to request. Default is "message".

	* @return string

	*/

	function lastActionStatus($request = "message") {

		return $this->return_status[0]["$request"];

	}



	/**

	* Append a random string to url to fool proxy

	*

	* @param string $type Set to "nodash" if you do not want a dash ("-") in random string. Otherwise just leave it blank.

	* @access private

	* @return string Complete URL

	* @author Neerav

	* @since June 2005

	*/

	function proxy_defeat($type = "") {

		$length = 12;

		$seeds = 'abcdefghijklmnopqrstuvwxyz0123456789';

		$string = '';

		$seeds_count = strlen($seeds);

	 	 

		// Generate

		// Changed to also use without dash; by Neerav; 11 Aug 2005

		if ($type == "nodash") {

			for ($i = 0; $length > $i; $i++) {

				$string .= $seeds{mt_rand(0, $seeds_count - 1)};

			}

		} else {

			for ($i = 0; $length > $i; $i++) {

				$string .= $seeds{mt_rand(0, $seeds_count - 1)};

				if ($i == 5) $string .= "-";	// Added by Neerav; 28 June 2005

			}

		}

	 

		return "&zx=".$string;

	}



	/**

	* Fetch contents by URL query. 

	*

	* This is a "low-level" method. Please use {@link GMailer::fetchBox()} for fetching standard contents.

	*

	* @param string $query URL query string

	* @return bool Success or not

	*/

	function fetch($query) {

		if ($this->isConnected() == true) {

			Debugger::say("Start fetching query: ".$query);

			$query .= $this->proxy_defeat();	 // to fool proxy



			$this->gmail_data = GMailer::execute_curl(

				GM_LNK_GMAIL."?".$query,

				GM_LNK_REFER,

				'get'

			);

			GMailer::parse_gmail_response($this->gmail_data);



			Debugger::say("Fetch completed.");

			return 1;

		

		} else {	  // not logged in yet				 

			Debugger::say("Fetch FAILED: not connected.");

			return 0;

			

		}

	}

	

	/**

	* Fetch contents from Gmail by type.

	*

	* Content can be one of the following categories:

	* 1. {@link GM_STANDARD}: For standard mail-boxes like Inbox, Sent Mail, All, etc. In such case, $box should be the name of the mail-box: "inbox", "all", "sent", "draft", "spam", or "trash". $paramter would be used for paged results.

	* 2. {@link GM_LABEL}: For user-defined label. In such case, $box should be the name of the label.

	* 3. {@link GM_CONVERSATION}: For conversation. In such case, $box should be the conversation ID and $parameter should be the mailbox/label in which the message is found (if supplied 0, it will default to "inbox").

	* 4. {@link GM_QUERY}: For search query. In such case, $box should be the query string.

	* 5. {@link GM_PREFERENCE}: For Gmail preference. In such case, $box = "".

	* 6. {@link GM_CONTACT}: For contact list. In such case, $box can be either "all", "search", "detail", "group", or "group detail". When $box = "detail", $parameter is the Contact ID. When $box = "search", $parameter is the search query string.

	*

	* @return bool Success or not

	* @param constant $type Content category 

	* @param mixed $box Content type

	* @param int $parameter Extra parameter. See above.

	* @see GM_STANDARD, GM_LABEL, GM_CONVERSATION, GM_QUERY, GM_PREFERENCE, GM_CONTACT

	*/

	function fetchBox($type, $box, $parameter) {

		if ($this->isConnected() == true) {

			switch ($type) {

				case GM_STANDARD:

					$q = "search=".strtolower($box)."&view=tl&start=".$parameter;

					break;

				case GM_LABEL:

					$q = "search=cat&cat=".$box."&view=tl&start=".$parameter;

					break;

				case GM_CONVERSATION:

					if ($parameter === 0 or $parameter == "") $parameter = "inbox";

					if (in_array(strtolower($parameter),$this->gmail_reserved_names)) {

						$q = "search=".urlencode($parameter)."&ser=1&view=cv";

					} else {

						$q = "search=cat&cat=".urlencode($parameter)."&ser=1&view=cv";

					}

					if (is_array($box)) {

						$q .= "&th=".$box[0];

						for ($i = 1; $i < count($box); $i++)

							$q .= "&msgs=".$box[$i];

					} else {

						$q .= "&th=".$box;

					}

					break;

				case GM_QUERY:

					$q = "search=query&q=".urlencode($box)."&view=tl&start=".$parameter;

					break;

				case GM_PREFERENCE:

					$q = "view=pr&pnl=g";

					break;

				case GM_CONTACT:

					if (strtolower($box) == "all")

						$q = "view=cl&search=contacts&pnl=a";

					elseif (strtolower($box) == "search")	// Added by Neerav; 15 June 2005

						$q = "view=cl&search=contacts&pnl=s&q=".urlencode($parameter);

					elseif (strtolower($box) == "detail")	// Added by Neerav; 1 July 2005

						$q = "search=contacts&ct_id=".$parameter."&cvm=2&view=ct".$this->proxy_defeat();

					elseif (strtolower($box) == "group_detail")	// Added by Neerav; 6 Jan 2006

						$q = "search=contacts&ct_id=".$parameter."&cvm=1&view=ctl".$this->proxy_defeat();

					elseif (strtolower($box) == "group")

						$q = "view=cl&search=contacts&pnl=l";

					else // frequently mailed

						$q = "view=cl&search=contacts&pnl=p";

					break;						

				default:

					$q = "search=inbox&view=tl&start=0&init=1";

					break;

			}

			$this->fetch($q);

			return true;

		} else {

			return false;

		}

	}		 

	

	/**

	* Save all attaching files of conversations to a path.

	*

	* Random number will be appended to the new filename if the file already exists.

	*

	* @return string[] Name of the files saved. False if failed.

	* @param string[] $convs Conversations.

	* @param string $path Local path.

	*/

	function getAttachmentsOf($convs, $path) {

		if ($this->isConnected() == true) {

			if (!is_array($convs)) {

				$convs = array($convs);	 // array wrapper

			}

			$final = array();

			foreach ($convs as $v) {

				if (count($v["attachment"]) > 0) {

					foreach ($v["attachment"] as $vv) {

						$f = $path."/".$vv["filename"];

						while (file_exists($f)) {

							$f = $path."/".$vv["filename"].".".round(rand(0,1999));

						}

						if ($this->getAttachment($vv["id"],$v["id"],$f,false)) {

							array_push($final, $f);

						}

					}

				}

			}

			return $final;

		} else {

			return false;

		}

	}								

	

	/**

	* Save attachment with attachment ID $attid and message ID $msgid to file with name $filename.

	*

	* @return bool Success or not.

	* @param string $attid Attachment ID.

	* @param string $msgid Message ID.

	* @param string $filename File name.

	* @param bool $zipped Save all attachment of message ID $msgid into a zip file.

	*/

	function getAttachment($attid, $msgid, $filename, $zipped=false) {

		if ($this->isConnected() == true) {

			Debugger::say("Start getting attachment...");

			

			if (!$zipped)

				$query = GM_LNK_GMAIL."?view=att&disp=attd&attid=".urlencode($attid)."&th=".urlencode($msgid);					  

/* 			else  */

/* 				$query = GM_LNK_GMAIL."?view=att&disp=zip&th=".urlencode($msgid); */



/* 				$query = GM_LNK_ATTACHMENT."&attid=".urlencode($attid)."&th=".urlencode($msgid);					   */

			else 

				$query = GM_LNK_ATTACHMENT_ZIPPED."&th=".urlencode($msgid);

					

			$fp = fopen($filename, "wb");

			if ($fp) {

				$c = curl_init();

				curl_setopt($c, CURLOPT_FILE, $fp);

				curl_setopt($c, CURLOPT_COOKIE, $this->cookie_str);

				curl_setopt($c, CURLOPT_URL, $query);

				curl_setopt($c, CURLOPT_FOLLOWLOCATION, 1);

				$this->CURL_PROXY($c);

				curl_setopt($c, CURLOPT_SSL_VERIFYHOST, 2);	 

				curl_setopt($c, CURLOPT_SSL_VERIFYPEER, FALSE);

				curl_setopt($c, CURLOPT_USERAGENT, GM_USER_AGENT);

				curl_setopt($c, CURLOPT_REFERER, GM_LNK_REFER);

				curl_exec($c);

				curl_close($c);

				fclose($fp);

			} else {

				Debugger::say("FAILED to get attachment: cannot fopen the file.");

				return false;

			}

			Debugger::say("Completed getting attachment.");

			return true;

		} else {

			Debugger::say("FAILED to get attachment: not connected.");

			return false;

		}

	}			

			

	/**

	* Dump everything to output.

	*

	* This is a "low-level" method. Use the method {@link GMailer::fetchBox()} to fetch standard contents from Gmail.

	*

	* @return string Everything received from Gmail.

	* @param string $query URL query string.

	*/

	function dump($query) {

		if ($this->isConnected() == true) {

			Debugger::say("Dumping...");

			$query .= $this->proxy_defeat();	 // to fool proxy

			$this->gmail_data = GMailer::execute_curl( 

				GM_LNK_GMAIL."?".$query, 

				GM_LNK_REFER, 

				'get', "", "noheader", ""

			);

			Debugger::say("Finished dumping ".strlen($this->gmail_data)." bytes.");			  

			return $this->gmail_data;

		} else {	  // not logged in yet				 

			Debugger::say("FAILED to dump: not connected.");

			return "";

		}

	}		 

	

	/**

	* Send Gmail. Or save a draft email.

	*

	* Examples:

	* <code>

	* <?php

	*    // Simplest usage: send a new mail to one person:

	*    $gmailer->send("who@what.com", "Hello World", "Cool!\r\nFirst mail!");

	*

	*    // More than one recipients. And with CC:

	*    $gmailer->send("who@what.com, boss@company.com",

	*                   "Hello World",

	*                   "This is second mail.",

	*                   "carbon-copy@company.com");

	*

	*    // With file attachment

	*    $gmailer->send("who@what.com", 

	*                   "Your file", 

	*                   "Here you are!", 

	*                   "", "", "", "", 

	*                   array("path/to/file.zip", "path/to/another/file.tar.gz"));

	*

	*    // more examples...

	* ? >

	* </code>

	*

	* @since 9 September 2005

	* @return bool Success or not. If returned false, please check {@link GMailer::$return_status} or {@link GMailer::lastActionStatus()} for error message.

	* @param string $to Recipient's address. Separated by comma for multiple recipients.

	* @param string $subj Subject line of email.

	* @param string $body Message body of email.

	* @param string $cc Address for carbon-copy (CC). Separated by comma for multiple recipients. $cc = "" for none.

	* @param string $bcc Address for blind-carbon-copy (BCC). Separated by comma for multiple recipients. $bcc = "" for none.

	* @param string $mid Message ID of the replying email. $mid = "" if this is a newly composed email.

	* @param string $tid Conversation (thread) ID of the replying email. $tid = "" if this is a newly composed email.	

	* @param string[] $files File names of files to be attached.

	* @param bool $draft Indicate this email is saved as draft, or not.

	* @param string $orig_df If this email is saved as a <i>modified</i> draft, then set $orig_df as the draft ID of the original draft.

	* @param bool $is_html HTML-formatted mail, or not.

	* @param array $attachments Attachments (forwards) in the form of 0_messageIDthatContainedTheAttachment_attachmentID (e.g. 0_17ab83d2f68n2b_0.1 , 0_17ab83d2f68n2b_0.2)

	* @param string $from Send mail as this email address (personality). $from = "" to use your Gmail address (NOT the default one in your settings). Note: you will NOT send your mail successfully if you do not register this address in your Gmail settings panel.

	*/

	function send($to, $subj, $body, $cc="", $bcc="", $mid="", $tid="", $files=0, $draft=false, $orig_df="", $is_html=0, $from="", $attachments = array()) {

		if ($this->isConnected()) {						

			$postdata = array();

			if ($draft == true) {

				$postdata["view"] 	= "sd";

				$postdata["draft"] 	= $orig_df;

				$postdata["rm"] 	= $mid;

				$postdata["th"] 	= $tid;			

			} else {

				$postdata["view"] 	= "sm";

				$postdata["draft"] 	= $orig_df;

				$postdata["rm"] 	= $mid;

				$postdata["th"] 	= $tid;								  

			}



			$postdata["at"] = $this->at_value();



			// These are in the POST form, but do not know what they are

			// or what their values should be

			// Send works ok despite these being left out.

/* 			$postdata["wid"] 	= 8; */

/* 			$postdata["jsid"] 	= xxxxxxxxxx; */

/* 			$postdata["ov"] 	= ""; */

			//$postdata["cmid"] 		= 1;		  



			if (strlen($from) > 0) {

			   $postdata["from"] = $from;

			}

			$postdata["to"] 		= stripslashes($to);

			$postdata["cc"] 		= stripslashes($cc);

			$postdata["bcc"] 		= stripslashes($bcc);

			$postdata["subject"] 	= stripslashes($subj);

			$postdata["ishtml"] 	= ($is_html) ? 1 : 0;

			$postdata["msgbody"] 	= stripslashes($body);

			

			// Added attachment/forward support; by Neerav; 22 Oct 2005

			// should be POST, but we fake it in GET

			$getdata = "";

			if (count($attachments) > 0) {

				for ($i=0; $i<count($attachments); $i++) {

					$getdata .= "&attach=".$attachments[$i];

				}

			}  

			

			$new_attach = 0;

			if (is_array($files)) {

				// an array of files supplied

				$new_attach = count($files);

				for ($i = 0; $i < $new_attach; $i++) {

					$postdata["file".$i] = "@".realpath($files[$i]);

				}

			} elseif ($files != 0) {

				// only one file attachment supplied

				$new_attach = 1;

				$postdata["file"] = "@".realpath($files);

			}

			//echo $postdata;

			// Changed to add attachment/forward support ($getdata); by Neerav; 22 Oct 2005

			$this->gmail_data = GMailer::execute_curl(

				GM_LNK_GMAIL."?&search=inbox&qt=&cmid=&newatt=".$new_attach."&rematt=0".$getdata,

/* 				GM_LNK_REFER, */

				GM_LNK_GMAIL."?&view=cv&search=inbox&th=".$tid/* ."&lvp=4&cvp=1" */."&qt=".$this->proxy_defeat("nodash"),

				'post',

				$postdata

			);

			GMailer::parse_gmail_response($this->gmail_data);



			// Added by Neerav; 12 July 2005

			$status = (isset($this->raw["sr"][2])) ? $this->raw["sr"][2] : false;

			$a = array(

				"action" 	=> "send email",

				// $this->raw["sr"][1] // what is this?? // always 1

				"status" 	=> ($status ? "success" : "failed"),

				"message" 	=> (isset($this->raw["sr"][3]) ? $this->raw["sr"][3] : ""),

				"thread_id"	=> (isset($this->raw["sr"][4]) ? $this->raw["sr"][4] : ""),

				// $this->raw["sr"][5] // what is this?? // always 0

				// $this->raw["sr"][6] // what is this?? // always an empty array

				// $this->raw["sr"][7] // what is this?? // always 0

				// $this->raw["sr"][8] // what is this?? // always 0

				// $this->raw["sr"][9] // what is this?? // always 0

				// $this->raw["sr"][10] // what is this?? // always blank (or false)

				// $this->raw["sr"][11] // what is this?? // some kind of message/server id, but doesn't match any header

				// $this->raw["sr"][12] // what is this?? // always 0

				"sent_num"  => ((isset($this->raw["aa"][1])) ? count($this->raw["aa"][1]) : 0)

			);

			array_unshift($this->return_status, $a);

			// Changed by Neerav; 12 July 2005

			return $status;

		} else {

			// Added by Neerav; 12 July 2005

			$a = array(

				"action" 		=> "send email",

				"status" 		=> "failed",

				"message" 		=> "libgmailer: not connected.",

				"thread_id" 	=> $tid,

				"sent_num"  	=> 0

			);

			array_unshift($this->return_status, $a);



			return false;

		}

	}

			

	/**

	* Perform action on messages.

	*

	* Examples:

	* <code>

	* <?php

	*    // Apply label to $message_id

	*    $gmailer->performAction(GM_ACT_APPLYLABEL, $message_id, "my_label");

	*

	*    // Star $message_id

	*    $gmailer->performAction(GM_ACT_STAR, $message_id);

	*

	*    // more examples...

	* ? >

	* </code>

	*

	* @return bool Success or not. If returned false, please check {@link GMailer::$return_status} or {@link GMailer::lastActionStatus()} for error message.

	  Additional return: Gmail returns a full datapack in response

	* @param constant $act Action to be performed.

	* @param string[] $id Message ID.

	* @param string $para Action's parameter:

	* 1. {@link GM_ACT_APPLYLABEL}, {@link GM_ACT_REMOVELABEL}: Name of the label.

	* @param string[] $mailbox Standard/Label mailbox name.  If this left out, actions will only work on messages in the Inbox.

	*/

	function performAction($act, $id, $para="", $mailbox="") {

		// Fixed (un)trash, added delTrashedMsgs action; by Neerav; 27 Feb 2006

/* 				$this->gmail_data = GMailer::execute_curl( */

/* 					GM_LNK_GMAIL."?".$link */

/* 					GM_LNK_GMAIL."?".$referrer, */

/* 					'post', */

/* 					$postdata */

/* 				); */

		if ($this->isConnected()) {			

			$postdata = "";

			$referrer = GM_LNK_REFER;

			$action_codes = array(

				"ib", 	// nothing / placeholder

				"ac_", 	// GM_ACT_APPLYLABEL

				"rc_", 	// GM_ACT_REMOVELABEL

				"st", 	// GM_ACT_STAR

				"xst", 	// GM_ACT_UNSTAR

				"sp", 	// GM_ACT_SPAM

				"us", 	// GM_ACT_UNSPAM

				"rd", 	// GM_ACT_READ

				"ur", 	// GM_ACT_UNREAD

				"tr", 	// GM_ACT_TRASH

				"dl", 	// GM_ACT_DELFOREVER

				"rc_^i", // GM_ACT_ARCHIVE

				"ib", 	// GM_ACT_INBOX

				"ib", 	// GM_ACT_UNTRASH

				"dd", 	// GM_ACT_UNDRAFT

				"dm", 	// GM_ACT_TRASHMSG

				"dl", 	// GM_ACT_DELSPAM

				"dl",	// GM_ACT_DELTRASHED

				"rtr",	// GM_ACT_UNTRASHMSG

				"dt"	// GM_ACT_DELTRASHEDMSGS

			);



			if ($act == GM_ACT_DELFOREVER)

				$this->performAction(GM_ACT_TRASH, $id, 0, $mailbox);	// trash it before

			

			//$postdata .= "ik=".$this->cookie_ik_str;



			$postdata .= "&act=";

			

			$postdata .= (isset($action_codes[$act])) ? $action_codes[$act] : $action_codes[GM_ACT_INBOX];

			if ($act == GM_ACT_APPLYLABEL || $act == GM_ACT_REMOVELABEL) {

				$postdata .= $para;

			}

			$postdata .= "&at=".$this->at_value();

			

			if ($act == GM_ACT_TRASHMSG || $act == GM_ACT_UNTRASHMSG) {

				$postdata .= "&m=".$id;

			} else {

				if (is_array($id)) {

					foreach ($id as $t) {

						$postdata .= "&t=".$t;

					}

				} else {

					$postdata .= "&t=".$id;

				}

				if ($act != GM_ACT_DELTRASHEDMSGS) {

					$postdata .= "&vp=";

					$postdata .= "&msq=";			// Added by Neerav; 25 Nov 2005

					$postdata .= "&ba=false";		// Added by Neerav; 25 Nov 2005

				}

			}

			

			if ($act == GM_ACT_UNTRASH || $act == GM_ACT_DELFOREVER || $act == GM_ACT_DELTRASHED) {

				$query = "&search=trash";

			} elseif ($act == GM_ACT_DELSPAM) {

				$query = "&search=spam";

			} elseif ($mailbox != "") {

				switch ($mailbox) {

					case "inbox": 	$box_type = "std";	break;

					case "starred": $box_type = "std";	break;

					case "sent": 	$box_type = "std";	break;

					case "drafts": 	$box_type = "std";	break;

					case "all": 	$box_type = "std";	break;

					case "spam": 	$box_type = "std";	break;

					case "trash": 	$box_type = "std";	break;

					case "chats": 	$box_type = "std";	break;

					default: 		$box_type = "label";	break;

				}



				if ($box_type == "std") {

					$query = "&search=".$mailbox;

				} else {

					$query = "&search=cat&cat=".urlencode($mailbox);

					$referrer = GM_LNK_GMAIL."?&search=cat&cat=".urlencode($mailbox)."&view=tl&start=0".$this->proxy_defeat();

				}

			} else {

				$query = "&search=query&q=";

			}

/* 			print(GM_LNK_GMAIL."?"."&qt=".$query."&view=up".$postdata.$this->proxy_defeat()); */



			if ($act == GM_ACT_TRASHMSG || $act == GM_ACT_UNTRASHMSG || $act == GM_ACT_DELTRASHEDMSGS) {

				$this->gmail_data = GMailer::execute_curl(

					GM_LNK_GMAIL."?"."&qt=".$query."&view=up".$postdata.$this->proxy_defeat(),

					"",

					'get'

				);

			} else {

				$this->gmail_data = GMailer::execute_curl(

					GM_LNK_GMAIL."?".$query."&view=tl&start=0",

					$referrer,

					'post',

					$postdata

				);

			}

			GMailer::parse_gmail_response($this->gmail_data);

			

			// Added additional return info; by Neerav; 13 July 2005

			$status  = (isset($this->raw["ar"][1])) ? $this->raw["ar"][1] : 0;

			$message = (isset($this->raw["ar"][2])) ? $this->raw["ar"][2] : "";

			$a = array(

				"action" 		=> "message action",

				"status" 		=> (($status) ? "success" : "failed"),

				"message" 		=> $message

			);

			array_unshift($this->return_status, $a);

			return $status;

		} else {

			// Added by Neerav; 12 July 2005

			$a = array(

				"action" 		=> "message action",

				"status" 		=> "failed",

				"message" 		=> "libgmailer: not connected"

			);

			array_unshift($this->return_status, $a);



			return false;

		}

	}			

	

	/**

	* @return bool Success or not.

	* @desc Recover session information.

	*/

	function getSessionFromBrowser() {

		Debugger::say("Start getting session from browser...");

		

		if (!$this->use_session) {

			return $this->getCookieFromBrowser();

		}

		// Changed to support IK; by Neerav; 13 July 2005

		// Last modified by Neerav; 14 Aug 2005

		if (isset($_SESSION[GM_COOKIE_KEY])) {

			$this->cookie_str = base64_decode($_SESSION[GM_COOKIE_KEY]);

			Debugger::say("Completed getting session from server: ".$this->cookie_str);



			if (isset($_SESSION['id_key'])) {

				$this->cookie_ik_str = $_SESSION['id_key'];

				Debugger::say("Completed getting ik from server: ".$this->cookie_ik_str);

			} else {

				Debugger::say("FAILED to read id_key from server.");

			}

			return true;

		} else {

			Debugger::say("FAILED to read ".GM_COOKIE_KEY." or ".'id_key'." from server.");

/* 			Debugger::say("FAILED to read cookie ".GM_COOKIE_KEY." from browser."); */

			return false;

		}

	}

	

	/**

	* @return bool Success or not.

	* @desc Get cookies from browser.

	*/

	function getCookieFromBrowser() {

		Debugger::say("Start getting cookie from browser...");

		

		if (!isset($_COOKIE)) {

			Debugger::say("FAILED to get any cookie from browser.");

			return false;

		}

		if (count($_COOKIE) == 0) {

			Debugger::say("FAILED to get non-empty cookie array from browser.");

			return false;

		}

		// Changed to support IK cookie; by Neerav; 8 July 2005

		// Disabled IK cookie requirement

		//if (isset($_COOKIE[GM_COOKIE_KEY]) and isset($_COOKIE[GM_COOKIE_IK_KEY])) {

 		if (isset($_COOKIE[GM_COOKIE_KEY])) {

			$this->cookie_str = base64_decode($_COOKIE[GM_COOKIE_KEY]);

			Debugger::say("Completed getting cookie from browser: ".$this->cookie_str);



			if (isset($_COOKIE[GM_COOKIE_IK_KEY])) {

				$this->cookie_ik_str = base64_decode($_COOKIE[GM_COOKIE_IK_KEY]);

				Debugger::say("Completed getting ik cookie from browser: ".$this->cookie_ik_str);

			}

			return true;

		} else {

			//Debugger::say("FAILED to read cookie ".GM_COOKIE_KEY." or ".GM_COOKIE_IK_KEY." from browser.");

			Debugger::say("FAILED to read cookie ".GM_COOKIE_KEY." from browser.");

			return false;

		}

	}		 

	

	/**

	* @return bool Success or not.

	* @desc Save session data.

	*/

	function saveSessionToBrowser() {

		Debugger::say("Start saving session to server/browser...");

		

		if ($this->isConnected()) {

			if (!$this->use_session)

				return $this->saveCookieToBrowser();				

			

			$_SESSION[GM_COOKIE_KEY] = base64_encode($this->cookie_str);

			Debugger::say("Just saved session: ".GM_COOKIE_KEY."=".base64_encode($this->cookie_str));

			Debugger::say("Completed saving session to server.");

			return true;

		}

		Debugger::say("FAILED to save session to server/browser: not connected.");

		return false;

	}

	

	/**

	* @return bool Success or not.

	* @desc Save (send) cookies to browser.

	*/

	function saveCookieToBrowser() {			  

		Debugger::say("Start saving cookie to browser...");			

		if ($this->isConnected()) {

			

			if (strpos($_SERVER["HTTP_HOST"],":"))

				$domain = substr($_SERVER["HTTP_HOST"],0,strpos($_SERVER["HTTP_HOST"],":"));

			else

				$domain = $_SERVER["HTTP_HOST"];

			Debugger::say("Saving cookies with domain=".$domain);

				

			header("Set-Cookie: ".GM_COOKIE_KEY."=".base64_encode($this->cookie_str)."; Domain=".$domain.";");

			//setcookie(GM_COOKIE_KEY, base64_encode($this->cookie_str), 1209600, "/" , $domain);

			Debugger::say("Just saved cookie: ".GM_COOKIE_KEY."=".base64_encode($this->cookie_str));

			Debugger::say("Completed saving cookie to browser.");

			return true;

		}

		Debugger::say("FAILED to save cookie to browser: not connected.");

		return false;

	}

	

	/**

	* @return bool Success or not.

	* @desc Remove all session information related to Gmailer.

	*/

	function removeSessionFromBrowser() {

		Debugger::say("Start removing session from browser...");

		

		if (!$this->use_session)

			return $this->removeCookieFromBrowser();

		

		// Changed/Added by Neerav; 6 July 2005

		// determines whether session should be preserved or normally destroyed

		if (GM_USE_LIB_AS_MODULE) {

			// if this lib is used as a Gmail module in some other app (e.g. 

			//     "online office"), don't destroy session



			// Let's unset session variables

			if (isset($_SESSION[GM_COOKIE_KEY])) unset($_SESSION[GM_COOKIE_KEY]);

			if (isset($_SESSION['id_key'])) unset($_SESSION['id_key']);

			Debugger::say("Cleared libgmailer related session info.");

			Debugger::say("Session preserved for other use.");

		} else {

			// otherwise (normal) unset and destroy session

			@session_unset();

			@session_destroy();

			Debugger::say("Just removed session: ".GM_COOKIE_KEY);

			Debugger::say("Finished removing session from browser.");

		}

		return true;

	}

	

	/**

	* @return bool

	* @desc Remove all related cookies stored in browser.

	*/

	function removeCookieFromBrowser() {

		Debugger::say("Start removing cookie from browser...");

		if (isset($_COOKIE)) {

			// Changed to include IK cookie; by Neerav; 8 July 2005

			if (isset($_COOKIE[GM_COOKIE_KEY]) or isset($_COOKIE[GM_COOKIE_IK_KEY])) {

				// libgmailer cookies exist

				if (strpos($_SERVER["HTTP_HOST"],":"))

					$domain = substr($_SERVER["HTTP_HOST"],0,strpos($_SERVER["HTTP_HOST"],":"));

				else

					$domain = $_SERVER["HTTP_HOST"];

				Debugger::say("Removing cookies with domain=".$domain);					 

				

				header("Set-Cookie: ".GM_COOKIE_KEY."=1; Discard; Max-Age=0; Domain=".$domain.";");

				header("Set-Cookie: ".GM_COOKIE_IK_KEY."=0; Discard; Max-Age=0; Domain=".$domain.";");

				Debugger::say("Just removed cookies: ".GM_COOKIE_KEY." and ".GM_COOKIE_IK_KEY);

				return true;

			} else {

				Debugger::say("Cannot find libgmailer cookies: ".GM_COOKIE_KEY." or ".GM_COOKIE_IK_KEY);

				return false;

			}

		} else {

			Debugger::say("Cannot find any cookie from browser.");

			return false;

		}

	}					 

	

	/**

	* @return void

	* @desc Disconnect from Gmail.

	*/

	function disconnect() {

		Debugger::say("Start disconnecting...");

		

		/** logout from mail.google.com too **/

		$this->gmail_data = GMailer::execute_curl(

			GM_LNK_GMAIL."?logout&hl=en".$this->proxy_defeat("nodash"),

			//http://mail.google.com/mail/?&ik=&search=inbox&view=tl&start=0&init=1&zx=csp670w0j1ar

			GM_LNK_GMAIL."?&ik=&search=inbox&view=tl&start=0&init=1".$this->proxy_defeat("nodash"),

			'get'

		);

		//GMailer::parse_gmail_response($this->gmail_data);

		//Debugger::say("logout: ".$this->gmail_data);



		// Updated by Neerav; 28 June 2005

		//curl_setopt($c, CURLOPT_URL, GM_LNK_LOGOUT);

		//curl_setopt($c, CURLOPT_URL, GM_LNK_GMAIL."?logout&hl=en&zx=".$this->proxy_defeat());

		// "&ik=&" + this.Threads.LastSearch + "&view=tl&start=0&init=1&zx=" + this.MakeUniqueUrl();

		Debugger::say("Logged-out from GMail.");

		

		$this->removeSessionFromBrowser();

		$this->cookie_str = "";

		$this->cookie_ik_str = "";	// Added to support IK; by Neerav; 13 July 2005

		

		Debugger::say("Completed disconnecting.");

	}

	

	/**

	* Get {@link GMailSnapshot} by type.

	*

	* Examples:

	* <code>

	* <?php

	*    // For "Inbox"

	*    $gmailer->fetchBox(GM_STANDARD, "inbox", 0);

	*    $snapshot = $gmailer->getSnapshot(GM_STANDARD);

	*

	*    // For conversation

	*    $gmailer->fetchBox(GM_CONVERSATION, $thread_id, 0);

	*    $snapshot = $gmailer->getSnapshot(GM_CONVERSATION);

	* ? >

	* </code>

	*

	* @return GMailSnapshot

	* @param constant $type

	* @see GMailSnapshot

	* @see GM_STANDARD, GM_LABEL, GM_CONVERSATION, GM_QUERY, GM_PREFERENCE, GM_CONTACT	

	*/

	function getSnapshot($type) {

		// Comment by Neerav; 9 July 2005

		// $type slowly will be made unnecessary as we move towards included all response

		//     fields in the snapshot

		

		if (!($type & (GM_STANDARD|GM_LABEL|GM_CONVERSATION|GM_QUERY|GM_PREFERENCE|GM_CONTACT))) {

			// if not specified, assume normal by default

			$type = GM_STANDARD;

		}



		// Changed by Neerav; use_session Fix by Dave DeLong <daveATdavedelongDOTcom>; 9 July 2005

		// Added $this->gmail_data to handle http errors; by Neerav; 16 Sept 2005

		return new GMailSnapshot($type, $this->raw, $this->use_session,$this->gmail_data);

	}

	

	/**

	* Send an invite

	*

	* @return bool Success or not. Note that it will still be true even if $email is an illegal address.

	* @param string $email

	* @desc Send Gmail invite to $email

	*/

	function invite($email) {

		if ($this->isConnected()) {			

			$postdata = "act=ii&em=".urlencode($email);

			$postdata .= "&at=".$this->at_value();



			$this->gmail_data = GMailer::execute_curl(

				GM_LNK_GMAIL."?view=ii",

				GM_LNK_INVITE_REFER,

				'post',

				$postdata

			);

			// Added status message parsing and return; by Neerav; 6 Aug 2005

			GMailer::parse_gmail_response($this->gmail_data);

			

			// Added by Neerav; 6 Aug 2005

			$status  = (isset($this->raw["ar"][1])) ? $this->raw["ar"][1] : 0;

			$message = (isset($this->raw["ar"][2])) ? $this->raw["ar"][2] : "";

			$a = array(

				"action" 		=> "invite",

				"status" 		=> (($status) ? "success" : "failed"),

				"message" 		=> $message

			);

			array_unshift($this->return_status, $a);



			return $status;

		} else {

			// Added by Neerav; 6 Aug 2005

			$a = array(

				"action" 		=> "$action label",

				"status" 		=> "failed",

				"message" 		=> "libgmailer: not connected"

			);

			array_unshift($this->return_status, $a);



			return false;

		}

	}

	

	/**

	* Get names of standard boxes.

	*

	* @static

	* @return string[]

	* @deprecated

	*/

	function getStandardBox() {

		return array("Inbox","Starred","Sent","Drafts","All","Spam","Trash");

	}		 

	

	/**

	* Get raw packet Gmailer::$raw

	*

	* @access private

	* @return mixed

	*/

	function dump_raw() {

		return $this->raw;

	}		 



	/**

	* Get full contents of $gmail_data (complete response from Gmail)

	*

	* @access private

	* @return mixed

	* @author Neerav

	* @since 13 Aug 2005

	*/

	function debug_gmail_response() {

		return $this->gmail_data;

	}

		 

	/**

	* cURL "helper" for proxy.

	*

	* @access private

	* @return void

	* @param curl_descriptor $cc

	*/

	function CURL_PROXY($cc) {

		if (strlen($this->proxy_host) > 0) {

			curl_setopt($cc, CURLOPT_PROXY, $this->proxy_host);

			if (strlen($this->proxy_auth) > 0)

				curl_setopt($cc, CURLOPT_PROXYUSERPWD, $this->proxy_auth);

		}

	}

	

	/**

	* Extract cookies from HTTP header.

	*

	* @return string Cookies string

	* @param string $header HTTP header

	* @access private

	* @static

	*/

	function get_cookies($header) {

		$match = "";

		preg_match_all('!Set-Cookie: ([^;\s]+)($|;)!', $header, $match);

/* 		Debugger::say("header: ".print_r($header,true)."\n\ncookies: ".print_r($match,true));  */

		$cookie = "";

		foreach ($match[1] as $val) {

			if ($val{0} == '=') continue;

			// Skip over "expired cookies which were causing problems; by Neerav; 4 Apr 2006

			if ((strpos($val,"EXPIRED") !== false) or (strpos($val,"GoogleAccountsLocale_session") !== false)) continue;

			$cookie .= $val . "; ";

		}

		return substr($cookie, 0, -2);

	}



	/**

	* Process Gmail data packets.

	*

	* @access private

	* @static

	* @return mixed[]

	* @param string $input

	* @param int& $offset

	*/

	function parse_data_packet($input, &$offset) {

		$output = array();

		

		// state variables

		$isQuoted = false;		// track when we are inside quotes

		$dataHold = "";			// temporary data container

		$lastCharacter = " ";



		// walk through the entire string

		for($i=1; $i < strlen($input); $i++) {

			switch($input[$i]) {

				case "[":	// handle start of array marker

					if(!$isQuoted) {

						// recurse any nested arrays

						array_push($output, GMailer::parse_data_packet(substr($input,$i), $offset));

						

						// the returning recursive function write out the total length of the characters consumed

						$i += $offset;

						

						// assume that the last character is a closing bracket

						$lastCharacter = "]";

					} else {

						$dataHold .= "[";

					}

					break;



				case "]":	// handle end of array marker

					if(!$isQuoted) {

						if($dataHold != "") {

							array_push($output, $dataHold);

						}

						

						// determine total number of characters consumed (write to reference)

						$offset = $i;

						return $output;

					} else {

						$dataHold .= "]";

						break;

					}



				case '"':	// toggle quoted state

					if($isQuoted) {

						$isQuoted = false;

					} else {

						$isQuoted = true;

						$lastCharacter = '"';

					}

					break;



				case ',':	// find end of element marker and add to array

					if(!$isQuoted) {

						if($dataHold != "") {	// this is to filter out adding extra elements after an empty array

							array_push($output, $dataHold);

							$dataHold = "";

						} else if($lastCharacter == '"') {	 // this is to catch empty strings

							array_push($output, "");

						}

					} else {

						$dataHold .= ",";

					}

					break;

					

				case '\\':

					if ($i < strlen($input) - 1) { 

						switch($input[$i+1]) {

							case "\\":							/* for the case \\ */

								// Added by Neerav; June 2005

								// strings that END in \ are now handled properly

								if ($i < strlen($input) - 2) { 

									switch($input[$i+2]) {

										case '"':							/* for the case \\" */

											$dataHold .= '\\';

											$lastCharacter = '\\"';

											$i += 1;

											break;

										case "'":							/* for the case \\' */

											$dataHold .= "\\";

											$lastCharacter = "\\'";

											$i += 1;

											break;

										default:

									}							 

								} else {

									$dataHold .= '\\';

									$lastCharacter = '\\';

								}

								break;

							case '"':							/* for the case \" */

								$dataHold .= '"';

								$lastCharacter = '\"';

								$i += 1;

								break;

							case "'":							/* for the case \' */

								$dataHold .= "'";

								$lastCharacter = "\'";

								$i += 1;

								break;

							case "n":							/* for the case \n */

								$dataHold .= "\n";

								$lastCharacter = "\n";

								$i += 1;

								break;

							case "r":							/* for the case \r */								

								$dataHold .= "\r";

								$lastCharacter = "\r";

								$i += 1;

								break;

							case "t":							/* for the case \t */

							  $dataHold .= "\t";

							  $lastCharacter = "\t";

							  $i += 1;

							  break;

							default:

						}							 

					}

					break;



				default:	  // regular characters are added to the data container

					$dataHold .= $input[$i];

					break;

			}

		}	 

		return $output;

	}



	/**

	* Create/edit contact.

	*

	* Examples:

	* <code>

	* <?php

	*    // Add a new one

	*    $gmailer->editContact(-1, 

	*                          "John", 

	*                          "john@company.com", 

	*                          "Supervisor of project X", 

	*                          "");

	*

	*    // Add a new one with lots of details

	*    $gmailer->editContact(

	*       -1, 

	*       "Mike G. Stone",

	*       "mike@company.com",

	*       array(

	*          array(

	*             "phone" 		=> "123-45678",

	*             "mobile" 		=> "987-65432",

	*             "fax" 		=> "111-11111",

	*             "pager" 		=> "222-22222",

	*             "im" 			=> "34343434",

	*             "company" 	=> "22nd Century Fox",

	*             "position" 	=> "CEO",

	*             "other" 		=> "Great football player!",

	*             "address" 	=> "1 Fox Rd",

	*             "detail_name" => "Work"

	*           ),

	*          array(

	*             "phone" 		=> "1-23-4567",

	*             "mobile" 		=> "9-87-6543",

	*             "email" 		=> "mike.at.home@home.net",

	*             "im" 			=> "stonymike (yahoo)",

	*             "im" 			=> "stonymike@hotmail.com",

	*             "other" 		=> "Has huge collection of World Cup t-shirts",

	*             "address" 	=> "1 Elm Street",

	*             "detail_name" => "Home"

	*           )

	*        );

	*

	*    // Modified an existing one

	*    $gmailer->editContact($contact_id, 

	*                          "Old Name", 

	*                          "new_mail@company.com", 

	*                          "Old notes"

	*                       );

	* ? >

	* </code>

	*

	* Note: You must supply the old name even if you are not going to modify it, or it will

	* be changed to empty!

	*

	* @return bool Success or not.

	  Extended return: array(bool success/fail, string message, string contact_id)

	* @param string $contact_id  Contact ID for editing an existing one, or -1 for creating a new one

	* @param string $name Name

	* @param string $email Email address

	* @param string $notes Notes

	* @param mixed[][] $details Detailed information

	* @author Neerav

	* @since 15 Jun 2005

	*/

	function editContact($contact_id, $name, $email, $notes, $details=array()) {

		if ($this->isConnected()) {			

			$postdata = array();

 			$postdata["act"] 	= "ec";

 	 		$postdata["ct_id"] 	= "$contact_id";

 			$postdata["ct_nm"] 	= $name;

 			$postdata["ct_em"] 	= $email;

 			$postdata["ctf_n"] 	= $notes;



			// Added by Neerav; 1 July 2005

			// contact details

			if (count($details) > 0) {

				$i = 0;				// the detail number

				$det_num = '00';	// detail number padded to 2 numbers for gmail

				foreach ($details as $detail1) {

					$postdata["ctsn_"."$det_num"] = "Unnamed";	// default name if none defined later

					$address = "";								// default address if none defined later

					$k = 0;										// the field number supplied to Gmail

					$field_num = '00';							// must be padded to 2 numbers for gmail

					foreach ($detail1 as $detail) {

						$field_type = "";

						switch (strtolower($detail["type"])) {

							case "phone":		$field_type = "p";	break;

							case "email":		$field_type = "e";	break;

							case "mobile":		$field_type = "m";	break;

							case "fax":			$field_type = "f";	break;

							case "pager":		$field_type = "b";	break;

							case "im":			$field_type = "i";	break;

							case "company":		$field_type = "d";	break;

							case "position":	$field_type = "t";	break;	// t = title

							case "other":		$field_type = "o";	break;

							case "address":		$field_type = "a";	break;

							case "detail_name": $field_type = "xyz";	break;

							default:			$field_type = "o";	break;	// default to other

							//default:			$field_type = $detail["type"];	break;	// default to the unknown detail

						}

						if ($field_type == "xyz") {

							$postdata["ctsn_"."$det_num"] = $detail["info"];

						} elseif ($field_type == "a") {

							$address = $detail["info"];

						} else {

							// e.g. ctsf_00_00_p for phone

							$postdata["ctsf_"."$det_num"."_"."$field_num"."_"."$field_type"] = $detail["info"];

							// increments the field number and pads it

							$k++;

							$field_num = str_pad($k, 2, '0', STR_PAD_LEFT);

						}

					}				

					// Address field needs to be last

					// if more than one address was given, the last one found will be used

					if ($address != "") $postdata["ctsf_"."$det_num"."_"."$field_num"."_a"] = $address;



					// increment detail number

					$i++;

					$det_num = str_pad($i, 2, '0', STR_PAD_LEFT);

				}

			}



			$postdata["at"] = $this->at_value();

			$this->gmail_data = GMailer::execute_curl(

				GM_LNK_GMAIL."?view=up",

				GM_LNK_GMAIL."?&search=contacts&ct_id=1&cvm=2&view=ct",

				'post',

				$postdata

			);

			GMailer::parse_gmail_response($this->gmail_data);

			

			$orig_contact_id = $contact_id;

			if ($orig_contact_id == -1 and $this->raw["ar"][1]) {

				if (isset($this->raw["cov"][1][1])) $contact_id = $this->raw["cov"][1][1];

				elseif (isset($this->raw["a"][1][1])) $contact_id = $this->raw["a"][1][1];

				elseif (isset($this->raw["cl"][1][1])) $contact_id = $this->raw["cl"][1][1];

			}

/* 			Debugger::say((($orig_contact_id == -1) ? "add contact": "edit contact").": ".print_r($this->gmail_data,true)); */

			$status = $this->raw["ar"][1];

			$a = array(

				"action" 		=> (($orig_contact_id == -1) ? "add contact": "edit contact"),

				"status" 		=> (($status) ? "success" : "failed"),

				"message" 		=> $this->raw["ar"][2],

				"contact_id" 	=> "$contact_id"

			);

			array_unshift($this->return_status, $a);



			return $status;



		} else {

			$a = array(

				"action" 		=> (($orig_contact_id == -1) ? "add contact": "edit contact"),

				"status" 		=> "failed",

				"message" 		=> "libgmailer: not connected",

				"contact_id" 	=> "$contact_id"

			);

			array_unshift($this->return_status, $a);

			return false;

		}

	}



	/**

	* Add message's senders to contact list.

	*

	* @return bool

	* @param string $message_id Message ID

	* @author Neerav

	* @since 14 Aug 2005

	*/

	function addSenderToContact($message_id) {

		if ($this->isConnected()) {			

			$query  = "";

			$query .= "&ik=".$this->cookie_ik_str;

			$query .= "&search=inbox";

			$query .= "&view=up";

			$query .= "&act=astc";

			$query .= "&at=".$this->at_value();

			$query .= "&m=".$message_id;

			$query .= $this->proxy_defeat();	 // to fool proxy



			set_time_limit(150);

			$c = curl_init();

			curl_setopt($c, CURLOPT_URL, GM_LNK_GMAIL."?".$query);

			// NOTE: DO NOT SEND REFERRER

			$this->CURL_PROXY($c);

			curl_setopt($c, CURLOPT_HEADER, 1);

			curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);

			curl_setopt($c, CURLOPT_FOLLOWLOCATION, 1);

			curl_setopt($c, CURLOPT_SSL_VERIFYHOST,  2);

			curl_setopt($c, CURLOPT_SSL_VERIFYPEER, FALSE);

			curl_setopt($c, CURLOPT_USERAGENT, GM_USER_AGENT);

			curl_setopt($c, CURLOPT_COOKIE, $this->cookie_str);

			$this->gmail_data = curl_exec($c);

			GMailer::parse_gmail_response($this->gmail_data);

			curl_close($c);

			

			$a = array(

				"action" 		=> "add sender to contact list",

				"status" 		=> "success",

				"message" 		=> ""

			);

			array_unshift($this->return_status, $a);

			return true;

		} else {

			$a = array(

				"action" 		=> "add sender to contact list",

				"status" 		=> "failed",

				"message" 		=> "libgmailer: not connected"

			);

			array_unshift($this->return_status, $a);

			return false;

		}

	}



	/**

	* Star/unstar a message quickly.

	*

	* @return bool Success or not.

	  Extended return: array(bool success/fail, string message, string contact_id)

	* @param string $message_id

	* @param string $action Either "star" or "unstar".

	* @author Neerav

	8 @since 18 Aug 2005

	*/

	function starMessageQuick($message_id, $action) {

		if ($this->isConnected()) {			

			$query  = "";

			$query .= "&ik=".$this->cookie_ik_str;

			$query .= "&search=inbox";

			$query .= "&view=up";

			if ($action == "star") {

				$query .= "&act=st";

			} else {

				$query .= "&act=xst";

			}

			$query .= "&at=".$this->at_value();

			$query .= "&m=".$message_id;

			$query .= $this->proxy_defeat();	 // to fool proxy



			set_time_limit(150);

			$c = curl_init();

			curl_setopt($c, CURLOPT_URL, GM_LNK_GMAIL."?".$query);

			// NOTE: DO NOT SEND REFERRER

			$this->CURL_PROXY($c);

			curl_setopt($c, CURLOPT_HEADER, 1);

			curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);

			curl_setopt($c, CURLOPT_FOLLOWLOCATION, 1);

			curl_setopt($c, CURLOPT_SSL_VERIFYHOST,  2);

			curl_setopt($c, CURLOPT_SSL_VERIFYPEER, FALSE);

			curl_setopt($c, CURLOPT_USERAGENT, GM_USER_AGENT);

			curl_setopt($c, CURLOPT_COOKIE, $this->cookie_str);

			$this->gmail_data = curl_exec($c);

			GMailer::parse_gmail_response($this->gmail_data);

			curl_close($c);

			

			$status  = (isset($this->raw["ar"][1])) ? $this->raw["ar"][1] : 0;

			$message = (isset($this->raw["ar"][2])) ? $this->raw["ar"][2] : "";

			$a = array(

				"action" 		=> "$action message",

				"status" 		=> (($status) ? "success" : "failed"),

				"message" 		=> $message

			);

			array_unshift($this->return_status, $a);

			return $status;

		} else {

			$a = array(

				"action" 		=> "$action message",

				"status" 		=> "failed",

				"message" 		=> "libgmailer: not connected"

			);

			array_unshift($this->return_status, $a);

			return false;

		}

	}



	/**

	* Delete contacts.

	*

	* @return bool Success or not.

	  Extended return: array(bool success/fail, string message)

	* @param string[] $id Contact ID to be deleted

	* @author Neerav

	* @since 15 Jun 2005

	*/

	function deleteContact($id) {

		if ($this->isConnected()) {						

			$query 	 = "";



			if (is_array($id)) {

				//Post: act=dc&at=xxxxx-xxxx&cl_nw=&cl_id=&cl_nm=&c=0&c=3d

				$query .= "&act=dc&cl_nw=&cl_id=&cl_nm=";

				foreach ($id as $indexval => $contact_id) {

					$query .= "&c=".$contact_id;

				}

			} else {

				$query 	.= "search=contacts";

				$query 	.= "&ct_id=".$id;

				$query 	.= "&cvm=2";

				$query 	.= "&view=up";

				$query 	.= "&act=dc";

			}



			$query .= "&at=".$this->at_value();

			if (!is_array($id)) {

				$query .= "&c=".$id;

				$query .= $this->proxy_defeat();	 // to fool proxy

			}



			if (is_array($id)) {

				//URL: POST /gmail/?&ik=&view=up HTTP/1.1

				//Referer: http://mail.google.com/mail/?&ik=xxx&view=cl&search=contacts&pnl=a&zx=zfowhxlm2nrh

				$this->gmail_data = GMailer::execute_curl(

					GM_LNK_GMAIL."?view=up",

					GM_LNK_GMAIL."?view=cl&search=contacts&pnl=a",

					'post',

					$query

				);

			} else {

				$this->gmail_data = GMailer::execute_curl(

					GM_LNK_GMAIL."?".$query,

					GM_LNK_GMAIL."?view=cl&search=contacts&pnl=a",

					'get'

				);

			}

			GMailer::parse_gmail_response($this->gmail_data);

			

			$status = $this->raw["ar"][1];

			$a = array(

				"action" 		=> "delete contact",

				"status" 		=> (($status) ? "success" : "failed"),

				"message" 		=> $this->raw["ar"][2]

			);

			array_unshift($this->return_status, $a);

			return $status;

		} else {

			$a = array(

				"action" 		=> "delete contact",

				"status" 		=> "failed",

				"message" 		=> "libgmailer: not connected"

			);

			array_unshift($this->return_status, $a);

			return false;

		}

	}



	/**

	* Create, edit or remove label.

	* 

	* @return bool Success or not.

	  Extended return: array (boolean success/fail, string message)

	* @param string $label

	* @param string $action Either "create", "delete" or "rename"

	* @param string $renamelabel New name if renaming label

	* @author Neerav

	* @since 7 Jun 2005

	*/

	function editLabel($label, $action, $renamelabel) {

		if ($this->isConnected()) {			

			//Debugger::say("ik value: ".$this->cookie_ik_str);

				

			$postdata = array();

			if ($action == "create") {

				$postdata["act"] = "cc_".$label;

			} elseif ($action == "rename") {

				$postdata["act"] = "nc_".$label."^".$renamelabel;

			} elseif ($action == "remove") {

				$postdata["act"] = "dc_".$label;

			} else {

				// Changed by Neerav; 28 June 2005

				// was boolean, now array(boolean,string)

				$a = array(

					"action" 		=> "$action label",

					"status" 		=> (($status) ? "success" : "failed"),

					"message" 		=> "libgmailer error: unknown action in editLabel()"

				);

				array_unshift($this->return_status, $a);

				return false;

			}

			

			$postdata["at"] = $this->at_value();



			//Debugger::say(GM_LNK_GMAIL_HTTP."?&ik=".$_SESSION['id_key']."&view=pr&pnl=l".$this->proxy_defeat());

			$this->gmail_data = GMailer::execute_curl(

				GM_LNK_GMAIL_HTTP."?&ik=&view=up",

				GM_LNK_GMAIL_HTTP."?&ik=".$_SESSION['id_key']."&view=pr&pnl=l".$this->proxy_defeat(),

				'post',

				$postdata

			);

			GMailer::parse_gmail_response($this->gmail_data);



			// Changed by Neerav; 28 June 2005

			$status  = (isset($this->raw["ar"][1])) ? $this->raw["ar"][1] : 0;

			$message = (isset($this->raw["ar"][2])) ? $this->raw["ar"][2] : "";

			$a = array(

				"action" 		=> "$action label",

				"status" 		=> (($status) ? "success" : "failed"),

				"message" 		=> $message

			);

			array_unshift($this->return_status, $a);



			return $status;

		} else {

			// Added by Neerav; 12 July 2005

			$a = array(

				"action" 		=> "$action label",

				"status" 		=> "failed",

				"message" 		=> "libgmailer: not connected"

			);

			array_unshift($this->return_status, $a);



			return false;

		}

	}

	

	/**

	* Create/edit a filter.

	*

	* @return bool Success or not.

	  Extended return: array(bool,string message)

	* @param integer $filter_id Filter ID to be edited, or "0" for creating a new one

	* @param string $from

	* @param string $to

	* @param string $subject

	* @param string $has

	* @param string $hasnot

	* @param bool 	$hasAttach

	* @param bool	$archive

	* @param bool 	$star

	* @param bool 	$label

	* @param string $label_name

	* @param bool	$forward

	* @param string $forwardto

	* @param bool	$trash

	* @author Neerav

	* @since 25 Jun 2005

	*/

	function editFilter($filter_id, $from, $to, $subject, $has, $hasnot, $hasAttach,

				$archive, $star, $label, $label_name, $forward, $forwardto, $trash) {



		$action = ($filter_id == 0) ? "create" : "edit";		

		if ($this->isConnected()) {			

			$query = "";



			$query .= "view=pr";

			$query .= "&pnl=f";

			$query .= "&at=".$this->at_value();

			if ($action == "create") {

				// create new filter

				$query .= "&act=cf";

				$query .= "&cf_t=cf";

			} else {

				// edit existing filter

				$query .= "&act=rf";

				$query .= "&cf_t=rf";

			}

			

			$query .= "&cf1_from="	. urlencode($from);

			$query .= "&cf1_to="	. urlencode($to);

			$query .= "&cf1_subj="	. urlencode($subject);

			$query .= "&cf1_has="	. urlencode($has);

			$query .= "&cf1_hasnot=". urlencode($hasnot);

			$query .= "&cf1_attach="; $query .= ($hasAttach == true) ? "true" : "false" ;

			$query .= "&cf2_ar="	; $query .= ($archive == true) 	? "true" : "false" ;

			$query .= "&cf2_st="	; $query .= ($star == true) 	? "true" : "false" ;

			$query .= "&cf2_cat="	; $query .= ($label == true) 	? "true" : "false" ;

			$query .= "&cf2_sel="	. urlencode($label_name);

			$query .= "&cf2_emc="	; $query .= ($forward == true) 	? "true" : "false" ;

			$query .= "&cf2_email="	. urlencode($forwardto);

			$query .= "&cf2_tr="	; $query .= ($trash == true) 	? "true" : "false" ;

			if ($action == "edit") {

				$query .= "&ofid=".$filter_id;

			}

			$query .= $this->proxy_defeat();	 // to fool proxy



			$refer = "";

			$refer .= "&pnl=f";

			$refer .= "&search=cf";

			$refer .= "&view=tl";

			$refer .= "&start=0";

			$refer .= "&cf_f=cf1";

			$refer .= "&cf_t=cf2";

			$refer .= "&cf1_from="	. urlencode($from);

			$refer .= "&cf1_to="	. urlencode($to);

			$refer .= "&cf1_subj="	. urlencode($subject);

			$refer .= "&cf1_has="	. urlencode($has);

			$refer .= "&cf1_hasnot=". urlencode($hasnot);

			$refer .= "&cf1_attach="; $query .= ($hasAttach == true) 	? "true" : "false" ;

			if ($action == "edit") {

				$refer .= "&cf2_ar="	; $query .= ($archive == true) 	? "true" : "false" ;

				$refer .= "&cf2_st="	; $query .= ($star == true) 	? "true" : "false" ;

				$refer .= "&cf2_cat="	; $query .= ($label == true) 	? "true" : "false" ;

				$refer .= "&cf2_sel="	. urlencode($label_name);

				$refer .= "&cf2_emc="	; $query .= ($forward == true) 	? "true" : "false" ;

				$refer .= "&cf2_email="	. urlencode($forwardto);

				$refer .= "&cf2_tr="	; $query .= ($trash == true) 	? "true" : "false" ;

				$refer .= "&ofid="		. urlencode($filter_id);

			}

			$refer .= $this->proxy_defeat();	 // to fool proxy



			$this->gmail_data = GMailer::execute_curl(

				GM_LNK_GMAIL."?".$query,

				GM_LNK_GMAIL."?".$refer,

				'get'

			);

			GMailer::parse_gmail_response($this->gmail_data);

			

			//$updated_snapshot = new GMailSnapshot(GM_PREFERENCE, $this->raw, $this->use_session);

			$status = (isset($this->raw["ar"][1])) ? $this->raw["ar"][1] : 0;

			$message = (isset($this->raw["ar"][2])) ? $this->raw["ar"][2] : "";

			$a = array(

				"action" 		=> "$action filter",

				"status" 		=> (($status) ? "success" : "failed"),

				"message" 		=> $message

			);

			array_unshift($this->return_status, $a);



			return $status;

		} else {

			$a = array(

				"action" 		=> "$action filter",

				"status" 		=> "failed",

				"message" 		=> "libgmailer: not connected"

			);

			array_unshift($this->return_status, $a);

			return false;

		}

	}





	/**

	* Delete a filter.

	*

	* @return bool Success or not.

	  Extended return: array(bool success/fail, string message)

	* @param string $id Filter ID to be deleted

	* @author Neerav

	* @since 25 Jun 2005

	*/

	function deleteFilter($id) {

		if ($this->isConnected()) {			

			$query 	 = "";



			//PostData = "act=df_" + this.id.ToString() +

				//"&at=" + this.Parent.Cookies["GMAIL_AT"].Value;

			$query 	.= "act=df_".$id;



			$query 	.= "&at=".$this->at_value();

					

			$this->gmail_data = GMailer::execute_curl(

				GM_LNK_GMAIL."?ik=&view=up",

				GM_LNK_GMAIL."?pnl=f&view=pr".$this->proxy_defeat(),

				'post',

				$query

			);

			GMailer::parse_gmail_response($this->gmail_data);

			

			//$updated_snapshot = new GMailSnapshot(GM_PREFERENCE, $this->raw, $this->use_session);

			$status = (isset($this->raw["ar"][1])) ? $this->raw["ar"][1] : 0;

			$message = (isset($this->raw["ar"][2])) ? $this->raw["ar"][2] : "";

			$a = array(

				"action" 		=> "delete filter",

				"status" 		=> (($status) ? "success" : "failed"),

				"message" 		=> $message

			);

			array_unshift($this->return_status, $a);

			return $status;

		} else {

			$a = array(

				"action" 		=> "delete filter",

				"status" 		=> "failed",

				"message" 		=> "libgmailer: not connected"

			);

			array_unshift($this->return_status, $a);

			return false;

		}

	}





	/**

	* Edit contact groups.

	*

	* @return bool Success or not.

	  Extended return: array(bool success/fail, string message)

	* @param string $id Contact group ID to "edit" (-1 if creating a new group)

	* @param string $name Contact group's name

	* @param string $action Action to be performed on Contact group (rename, create, delete, remove_from, add_to)

	* @param string $data Data required for Action (optional depending on the Action)

	* @author Neerav

	* @since 10 Jan 2006

	*/

	function editGroup($id,$name,$action,$data = "") {

		if ($this->isConnected()) {			

			if ($action == "rename") {

				$refer = GM_LNK_GMAIL."?search=contacts&ct_id=".$id."&cvm=1&view=ctl".$this->proxy_defeat();



				$query['act'] = "rcl_".$id."^".$data;

				$query['at'] = $this->at_value();

				$query['cpt'] = "cpta";

				$query['cl_id'] = $id;

				$query['cl_nm'] = $name;



			} elseif ($action == "delete") {

				$refer = GM_LNK_GMAIL."?view=cl&search=contacts&pnl=l".$this->proxy_defeat();



				$query['act'] 	= "dcal";

				$query['at'] 	= $this->at_value();

				$query['cpt'] 	= "";

				$query['cl_nw'] = "";

				$query['cl_id'] = "";

				$query['cl_nm'] = "";

				$query['cl'] 	= $id;



			} elseif ($action == "create") {

				$refer = GM_LNK_GMAIL."?view=nctl&search=contacts".$this->proxy_defeat();



				$query['act'] 	= "ancl";	// add new contact list

				$query['at'] 	= $this->at_value();

				$query['cl_nm'] = $name;

				$query['ce'] 	= (is_array($data)) ? implode(", ",$data) : $data;



			} elseif ($action == "remove_from") {

				$refer = GM_LNK_GMAIL."?search=contacts&ct_id=".$id."&cvm=1&view=ctl".$this->proxy_defeat();



				$query = "&act=rfcl";		// remove from contact list

				$query .= "&at=".$this->at_value();

				$query .= "&cpt=cpta";

				$query .= "&cl_id=".$id;

				$query .= "&cl_nm=".$name;

				$add_count = count($data);

				for ($i = 0; $i < $add_count; $i++) {

					$query .= "&cr=".$data[$i]['id']."/".$data[$i]['email'];

				}



			} elseif ($action == "add_to") {

				$refer = GM_LNK_GMAIL."?&search=contacts&ct_id=".$id."&cvm=1&view=ctl".$this->proxy_defeat();



				$query['act'] 	= "atcl";	// add to contact list

				$query['at'] 	= $this->at_value();

				$query['cpt'] 	= "cpta";

				$query['cl_id'] = $id;

				$query['cl_nm'] = $name;

				$query['ce'] 	= implode(", ",$data);



			} else {

				$a = array(

					"action" 		=> $action." contact group",

					"status" 		=> "failed",

					"message" 		=> "editGroup(): invalid ACTION"

				);

				array_unshift($this->return_status, $a);

				return false;

			}



			$this->gmail_data = GMailer::execute_curl(

				GM_LNK_GMAIL."?ik=&view=up",

				$refer,

				'post',

				$query

			);

			GMailer::parse_gmail_response($this->gmail_data);



			$status = (isset($this->raw["ar"][1])) ? $this->raw["ar"][1] : 0;

			$message = (isset($this->raw["ar"][2])) ? $this->raw["ar"][2] : "";

			$a = array(

				"action" 		=> $action." contact group",

				"status" 		=> (($status) ? "success" : "failed"),

				"message" 		=> $message

			);

			array_unshift($this->return_status, $a);

			return $status;

		} else {

			$a = array(

				"action" 		=> $action." contact group",

				"status" 		=> "failed",

				"message" 		=> "libgmailer: not connected"

			);

			array_unshift($this->return_status, $a);

			return false;

		}

	}

	/**

	* Set general, forwarding and POP settings of Gmail account.

	*

	* @return bool Success or not.

	  Extended return: array(bool status, string message)

	* @param bool $use_outgoing_name Use outgoing name (instead of the default)?

	* @param string $outgoing_name Outgoing name

	* @param bool $use_reply_email Use replying email address (instead of the default)?

	* @param string $reply_to Replying email address

	* @param string $language Language

	* @param int $page_length Page length: either 25, 50 or 100

	* @param bool $shortcut Enable keyboard shortcut?

	* @param bool $indicator Enable personal level indicator?

	* @param bool $snippet Enable snippet?

	* @param bool $custom_signature Enable custom signature?

	* @param string $signature Custom signature

	* @param bool $utf_encode Use utf-8 encoding?

	* @param bool $use_forwarding Forward all incoming messages?

	* @param string $forward_to Forward to this email address

	* @param string $forward_action What to do with forwarded message? (selected, archive, trash)

	* @param int $use_pop Enable POP access? {0 = disabled, 1 = enabled, 2 = from now, 3 = all}

	* @param int $pop_action What to do with forwarded message? {0 = keep, 1 = archive, 2 = trash}

	* @param bool $rich_text Use rich text formatting?

	* @param bool $expand_label_box Expand label box?

	* @param bool $expand_invite_box Expand invite box?

	* @param bool $vacation_on Vacation responder - ON/OFF

	* @param string $vacation_subject Vacation responder - Subject

	* @param string $vacation_message Vacation responder - Message

	* @param bool $vacation_contacts_only Vacation responder - Send vacation message only to those in Contacts list?

	* @param bool $chat_archive Save chat scripts

	* @param bool $aa_unknown ??

	* @author Neerav

	* @since 29 Jun 2005

	*/

	function setSetting(

				//$use_outgoing_name, $outgoing_name, $use_reply_email, $reply_to,

				$language, $page_length, $shortcut, $indicator, $snippet, $custom_signature, 

				$signature, $msg_encoding,

				$use_forwarding, $forward_to, $forward_action,

				$use_pop, $pop_action, $rich_text,

				$expand_label_box = 1, $expand_invite_box = 1,

				$vacation_on = 0, $vacation_subject = "", $vacation_message = "", $vacation_contacts_only = 0,

				$expand_talk_box = 1, $chat_archive = 0



		) {



		/* 	

	end vacation NOW:

GET http://mail.google.com/mail/?&ik=xxxxxxx&search=inbox&view=tl&start=0&act=prefs&at=xxxx-xxxx&p_bx_ve=0&zx=ferur3mmq41e HTTP/1.1

Referer: http://mail.google.com/mail/?&ik=xxxxxxx&view=pr&pnl=g&zx=xorfqampe0ml



		// general		

		"bx_hs"		// (boolean) keyboard shortcuts {0 = off, 1 = on}

		"bx_show0"	// (boolean) labels box {0 = collapsed, 1 = expanded}

		"ix_nt"		// (integer) msgs per page (maximum page size)

		"sx_dl"		// (string) display language (en = English, en-GB = British-english, etc)

		"bx_sc"		// (boolean) personal level indicators {0 = no indicators, 1 = show indicators}

		"bx_show1"	// (boolean) invite box {0 = collapsed, 1 = expanded}

		"sx_sg"		// (string) signature

		"bx_ns" 	// (boolean) no snippets {0 = show snippets, 1 = no snippets}

		"bx_cm" 	// (boolean) rich text composition {0 = plain text, 1 = rich text}

		"bx_en" 	// (boolean) outgoing message encoding {0 = default, 1 = utf-8}

		"bx_ve":	// (boolean) vacation message enabled {0 = OFF, 1 = ON}

		"sx_vs":	// (string) vacation message subject

		"sx_vm":	// (string) vacation message text

		"bx_vc":	// SPECIAL CASE (string to boolean) vacation message, send only to contacts list 

		"bx_show3"	// (boolean) gtalk box {0 = collapsed, 1 = expanded}



		// forwarding and pop

		"sx_em" 		// (string) forward to email address

		"sx_at" 		// (string) action after forwarding {selected, archive, trash} (selected means "keep")

		"bx_pe" 		// (integer) pop enabled {0 = disabled, 1 = enabled, 2 = from now, 3 = all}

		"ix_pd" 		// (integer) action after pop access {0 = keep, 1 = archive, 2 = trash}



		// mobile

		"sx_pf"			// (string) list of mailboxes to display in Gmail Mobile

		

		// other

		"bx_cm" 		// (boolean) rich text composition {0 = plain text, 1 = rich text}

		"bx_aa"			// ??



		// Chat

		"ix_ca"			// (boolean) save chat archives? {0 = off, 1 = on}



		// deprecated

		//"sx_dn" 	// (string) display name 

		//"sx_rt" 	// (string) reply to email address

		*/



		if ($this->isConnected()) {			

			$post_fields = array();

			$post_url = "";

			$query = "";



			//$query .= "&ik=".IKVALUE;

			$post_url .= "&view=up";

			$post_fields['act'] = "prefs";

			$post_url .= "&act=prefs";

			$post_fields['at'] = $this->at_value();

			$post_url .= "&at=".$this->at_value();

			$post_fields['search'] = "";



			$query .= "&sx_dl="		. $language;

			$query .= "&ix_nt="		. $page_length;

			$query .= "&bx_hs=";		$query .= ($shortcut) ? "1" : "0" ;

			$query .= "&bx_sc=";		$query .= ($indicator) ? "1" : "0" ;

			$query .= "&bx_ns=";		$query .= ($snippet) ? "0" : "1" ; // REVERSED because we originally reversed it for convenience

			$query .= "&sx_sg=";		$query .= $custom_signature;

			$query .= "&sx_sg=";		$query .= ($custom_signature) 	? urlencode($signature) 		: urlencode("\n\r") ;

			$query .= "&bx_ve=";		$query .= ($vacation_on) ? "1" : "0" ;

			$query .= "&sx_vs=";		$query .= urlencode($vacation_subject) ;

			$query .= "&sx_vm=";		$query .= urlencode($vacation_message) ;

			$query .= "&bx_en=";		$query .= ($msg_encoding) ? "1" : "0" ;

			$query .= "&ix_ca=";		$query .= ($chat_archive) ? "1" : "0" ;

/* 			$query .= "&ix_ql=10";		 */

/* 			$query .= "&bx_lq=0";		 */

/* 			$query .= "&bx_aa=1";		 */





			$post_fields['p_bx_hs'] = 		($shortcut) ? "1" : "0" ;

			$post_fields['p_bx_show0'] =	($expand_label_box) ? "1" : "0" ;

			$post_fields['p_ix_nt'] =		$page_length;

			$post_fields['p_bx_pe'] =		($use_pop >= 0 and $use_pop <= 3) ? $use_pop : "0" ;

			$post_fields['p_bx_show1'] =	($expand_invite_box) ? "1" : "0" ;

			$post_fields['p_bx_ve'] =		($vacation_on) ? "1" : "0" ;

			$post_fields['p_bx_cm'] =		($rich_text) ? "1" : "0" ;

			$post_fields['p_bx_en'] =		($msg_encoding) ? "1" : "0" ;

			$post_fields['p_ix_pd'] =		($pop_action >= 0 and $pop_action <= 2) ? $pop_action : "0" ;

/* 			$post_fields['p_ix_fv']	= 		"true"; */

			$post_fields['p_bx_show3'] =	($expand_talk_box) ? "1" : "0" ;

			$post_fields['p_sx_vm'] =		$vacation_message;

			$post_fields['p_sx_sg'] =		($custom_signature) 	? $signature		: "\n\r" ;

			$post_fields['p_sx_dl'] =		$language;

			$post_fields['p_bx_sc'] =		($indicator) ? "1" : "0" ;

			$post_fields['p_sx_vs'] =		$vacation_subject ;

			$post_fields['p_bx_ns'] =		($snippet) ? "0" : "1" ; // REVERSED because we originally reversed it for convenience

			$post_fields['p_sx_em'] =		($use_forwarding) 	? $forward_to 		: "" ;

			$post_fields['p_ix_ca'] = 		($chat_archive) ? "1" : "0" ;

/* 			$post_fields['p_bx_aa'] =1; */

/* 			$post_fields['p_ix_ql'] =10; */

/* 			$post_fields['p_bx_lq'] =0; */

			$post_fields['p_sx_at'] =		((   $forward_action == "selected"

													or $forward_action == "archive"

													or $forward_action == "trash"

											  ) ? $forward_action : "selected" 

											);

			// vacation responder; by Neerav; 21 Dec 2005

			// includes p_sx_vm p_sx_vs and p_bx_ve

			if ($vacation_contacts_only) {

				$post_fields['p_bx_vc'] = "true";

			} else {

				$post_fields['dp'] = "bx_vc";

			}



			//$post_fields['p_bx_aa'] = $aa_unknown;

			//http://mail.google.com/mail/?&ik=xxxxx&view=up&act=prefs&at=xxxx-xxxx



			$this->gmail_data = GMailer::execute_curl(

				GM_LNK_GMAIL."?".$post_url,

				GM_LNK_GMAIL."?&view=pr&pnl=g".$this->proxy_defeat(),

				'post',

				$post_fields

			);

			GMailer::parse_gmail_response($this->gmail_data);

			

			// get updated cookie

			ereg("S=gmail=([^\:]*):gmail_yj=([^\:]*):gmproxy=([^\;]*);",$this->gmail_data,$matches);

			$this->cookie_str = ereg_replace(

									"S=gmail=([^\:]*):gmail_yj=([^\:]*):gmproxy=([^\;]*);", 

									"S=gmail=".$matches[1].":gmail_yj=".$matches[2].":gmproxy=".$matches[3].";", 

									$this->cookie_str

								);

			// save updated cookie

			GMailer::saveSessionToBrowser();



			$status = (isset($this->raw["ar"][1])) ? $this->raw["ar"][1] : 0;

			$message = (isset($this->raw["ar"][2])) ? $this->raw["ar"][2] : "";

			$a = array(

				"action" 		=> "set settings",

				"status" 		=> (($status) ? "success" : "failed"),

				"message" 		=> $message

			);

			array_unshift($this->return_status, $a);

			return $status;

		} else {

			$a = array(

				"action" 		=> "set settings",

				"status" 		=> "failed",

				"message" 		=> "libgmailer: not connected"

			);

			array_unshift($this->return_status, $a);

			return false;

		}

	}



	function execute_curl($url, $referrer, $method, $post_data = "", $extra_type = "", $extra_data = "") {

		$message = '';

		

		if ($method != "get" and $method != "post") {

			$message = 'The cURL method is invalid.';

		}

		if ($url == "") {

			$message = 'The cURL url is blank.';

		}

/* 		if ($referrer == "") { */

/* 			$message = 'The cURL referrer is blank.'; */

/* 		} */

/* 		if ($method == "post" and (!is_array($data) or count($data) == 0)) { */

/* 			$message = 'The cURL post data  for POST is empty or invalid.'; */

/* 		} */



		// error

		if ($message != '') {

			array_unshift($this->return_status, array("action" => "execute cURL", "status" => "failed", "message" => $message));

			return;

		}

		

		set_time_limit(150);

		$c = curl_init();

		if ($method == "get") {

			curl_setopt($c, CURLOPT_URL, $url);

			if ($referrer != "") {

				curl_setopt($c, CURLOPT_REFERER, $referrer);

			}

			$this->CURL_PROXY($c);

			curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);

/* 			if ($extra_type == "nocookie") { */

/* 				curl_setopt($c, CURLOPT_FOLLOWLOCATION, 0); */

/* 			} else { */

				curl_setopt($c, CURLOPT_FOLLOWLOCATION, 1);

/* 			} */

			curl_setopt($c, CURLOPT_USERAGENT, GM_USER_AGENT);

			if ($extra_type != "noheader") {

				curl_setopt($c, CURLOPT_HEADER, 1);

			}

			if ($extra_type != "nocookie") {

				curl_setopt($c, CURLOPT_COOKIE, (($extra_type == "cookie") ? $extra_data : $this->cookie_str));				

			}

/* 			curl_setopt($c, CURLOPT_COOKIE, $this->cookie_str);				 */

		} elseif ($method == "post") {

			curl_setopt($c, CURLOPT_URL, $url);

			curl_setopt($c, CURLOPT_POST, 1);

			curl_setopt($c, CURLOPT_POSTFIELDS, $post_data);

			if ($referrer != "") {

				curl_setopt($c, CURLOPT_REFERER, $referrer);

			}

			$this->CURL_PROXY($c);

			curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);

			if ($extra_type == "nocookie") {

				curl_setopt($c, CURLOPT_FOLLOWLOCATION, 0);

			} else {

				curl_setopt($c, CURLOPT_FOLLOWLOCATION, 1);

			}

			curl_setopt($c, CURLOPT_USERAGENT, GM_USER_AGENT);

			curl_setopt($c, CURLOPT_HEADER, 1);

			if ($extra_type != "nocookie") {

				curl_setopt($c, CURLOPT_COOKIE, (($extra_type == "cookie") ? $extra_data : $this->cookie_str));				

			}

		}

		curl_setopt($c, CURLOPT_SSL_VERIFYHOST,  2);

		curl_setopt($c, CURLOPT_SSL_VERIFYPEER, FALSE);



/* 		// debugging cURL */

/* 		$fd = fopen("debug_curl.txt", "a+"); */

/* 		curl_setopt($c, CURLOPT_VERBOSE, 1); */

/* 		curl_setopt($c, CURLOPT_STDERR, $open_file_handle); */



		$gmail_response = curl_exec($c);

		curl_close($c);



/* 		// close debugging file */

/* 		fclose($fd); */

		

		return $gmail_response;

	}



	/**

	* Set Mobile settings of Gmail account.

	*

	* @return bool Success or not.

	  Extended return: array(bool status, string empty message)

	* @param array $mobile_display Array of standard boxes and labels to "display"

	* @author Neerav

	* @since 23 Dec 2005

	*/

	function setMobileSetting($mobile_display) {



		if ($this->isConnected()) {			

			$post = array();

			$get = "";

			$post['nvp_bu_done'] = "Save";

			$get .= "nvp_bu_done=Save";

			$post_url = "x/".$this->proxy_defeat("nodash")."-/?a=cfa";

			

			$post_url .= "&at=".$this->at_value();



			$count_mob_display = count($mobile_display);

			for ($i = 0; $i < $count_mob_display; $i++) {

				if (isset($mobile_display[$i]) and $mobile_display[$i] != "") {

/* 					$post['cfvc_'.$i] = urlencode($mobile_display[$i]); */

					$post['cfvc_'.$i] = $mobile_display[$i];

					$get .= "&cfvc_".$i."=".urlencode($mobile_display[$i]);

				}

			}



			$this->gmail_data = GMailer::execute_curl(

				GM_LNK_GMAIL_HTTP.$post_url,

				GM_LNK_GMAIL_HTTP."x/".$this->proxy_defeat("nodash")."-/?v=cmf",

				'post',

/* 				$post */

				$get

			);

			

/* 			print_r($post); */



/* 			Debugger::say("gmail response when setting mobile prefs: ".print_r($this->gmail_data,true)); */

			$status = (strstr($this->gmail_data,'<a href="?v=cmf">more views</a>') === false) ? 0 : 1;

			$a = array(

				"action" 		=> "set mobile settings",

				"status" 		=> (($status) ? "success" : "failed"),

				"message" 		=> ""

			);

			array_unshift($this->return_status, $a);

			return $status;

		} else {

			$a = array(

				"action" 		=> "set mobile settings",

				"status" 		=> "failed",

				"message" 		=> "libgmailer: not connected"

			);

			array_unshift($this->return_status, $a);

			return false;

		}

	}



	/**

	* Change Gmail Language

	*

	* @return bool Success or not.

	* @param string $old_lang Current language

	* @param string $new_lang New language

	* @author Neerav

	* @since 27 Nov 2005

	*/

	function changeLanguage($new_lang, $old_lang = "") {



		if ($this->isConnected()) {			

			$query = "";

			$refer = "";



			//$query .= "&ik=".IKVALUE;

			$query .= "&view=lpc&gfl=".(($old_lang != "")? $old_lang:"en")."&gtl=".$new_lang;

			//$refer .= "&ik=".IKVALUE;

			$refer .= "&view=pr&pnl=g";

			$refer .= $this->proxy_defeat();	 // to fool proxy



			$this->gmail_data = GMailer::execute_curl(

				GM_LNK_GMAIL."?".$query,

				GM_LNK_GMAIL."?".$refer,

				'get'

			);			



			//S=gmail=j8lv94EXSjI:gmail_yj=Fs3UajIqvjY:gmproxy=ZwcQ86EuvyY;

			ereg("S=gmail=([^\:]*):gmail_yj=([^\:]*):gmproxy=([^\;]*);",$this->gmail_data,$matches);

/* 			//Debugger::say("cookie matches: ".print_r($matches,true));			 */

			$this->cookie_str = ereg_replace(

									"S=gmail=([^\:]*):gmail_yj=([^\:]*):gmproxy=([^\;]*);", 

									"S=gmail=".$matches[1].":gmail_yj=".$matches[2].":gmproxy=".$matches[3].";", 

									$this->cookie_str

								);

/* 			//Debugger::say("new cookie: ".print_r($this->cookie_str,true));			 */



			// save updated cookie

			GMailer::saveSessionToBrowser();

			

			// GMAIL DOES NOT RESPOND WITH A STATUS MESSAGE



			$a = array(

				"action" 		=> "change language",

				"status" 		=> "success",

				"message" 		=> "(no message)"

			);

			array_unshift($this->return_status, $a);

			return true;

		} else {

			$a = array(

				"action" 		=> "change language",

				"status" 		=> "failed",

				"message" 		=> "libgmailer: not connected"

			);

			array_unshift($this->return_status, $a);

			return false;

		}

	}



	/**

	* Personalities / Custom FROM addresses

	*

	* @return bool Success or not.

	* @param string $action An action to perform: [set this address to] default, delete, reply_sent, reply_default, edit, edit_google, send_verify, verify_code

	* @param string $email

	* @param string $name

	* @param string $reply_to

	* @param integer $code Verification code for an added custom from address

	* @desc Custom From Address features

	* @author Neerav

	* @since 25 Feb 2006

	*/



	function customFrom($action, $email, $name = "", $reply_to = "", $code = "") {

		if ($this->isConnected()) {

			$url = "&ik=&view=up";

			$refer = "&view=pr&pnl=g".$this->proxy_defeat();

			$method = 'post';



			switch($action) {

				case "default":

				 	$postdata 	 = "act=mcf_".urlencode($email);

					$postdata 	.= "&at=".$this->at_value();

 					break;

				case "delete": 			

					$postdata  	 = "act=dcf_".urlencode($email);

					$postdata 	.= "&at=".$this->at_value();

 					break;

				case "reply_sent": 		

					$postdata  	 = "act=crf_1";

					$postdata 	.= "&at=".$this->at_value();

					$postdata 	.= "&search=";

 					break;

				case "reply_default": 	

					$postdata  	 = "act=crf_0";

					$postdata 	.= "&at=".$this->at_value();

					$postdata 	.= "&search=";

 					break;

 				case "edit":

					$postdata 	= "cfrp=1&cfe=1&cfn=".urlencode($name)."&cfrt=".urlencode($reply_to);

					$url 		= "&view=cf&cfe=true&cfa=".urlencode($email).$this->proxy_defeat();

					$refer 		= $url;

 					break;

 				case "edit_google":

					$postdata['cfrp'] 	= 1;

					$postdata['cfe'] 	= 1;

					$postdata['cfgnr'] 	= (($name != "")?1:0);

					$postdata['cfgn'] 	= $name;

					$postdata['cfrt'] 	= $reply_to;

					$url 		= "&view=cf&cfe=true&cfa=".urlencode($email).$this->proxy_defeat();

					$refer 		= $url;

 					break;

/* 				case "add_pre": */

/* 					$postdata 	= ""; */

/* 					$url 		= "&view=cf".$this->proxy_defeat(); */

/* 					$method		= 'get'; */

/*  					break; */

/* 				case "add": */

/* 					$postdata		 	= array(); */

/* 					$postdata['cfrp'] 	= 1; */

/* 					$postdata['cfn'] 	= $name; */

/* 					$postdata['cfa'] 	= $email; */

/* 					$postdata['cfrt'] 	= $reply_to; */

/* 					$url 				= "&view=cf"; */

/* 					$refer 				= $url; */

/*  					break; */

				case "send_verify":

					$postdata		 	= array();

					$postdata['cfrp'] 	= 2;

					$postdata['cfn'] 	= $name;

					$postdata['cfa'] 	= $email;

					$postdata['cfrt'] 	= $reply_to;

					$postdata['submit'] = "Send Verification";

					$url 				= "&view=cf";

					$refer 				= $url;

 					break;

				case "verify_code":

					$postdata		 	= array();

					$postdata['cfrp'] 	= 3;

					$postdata['cfrs'] 	= "false";

					$postdata['cfn'] 	= $name;

					$postdata['cfa'] 	= $email;

					$postdata['cfrt'] 	= $reply_to;

					$postdata['cfvc'] 	= $code;

					$url 				= "&view=cf";

					$refer 				= $url;

					break;

				default: 			

					array_unshift(

						$this->return_status, 

						array("action" => "custom from: $action",

							 "status" => "failed",

							 "message" => "libgmailer: Invalid action"

						)

					);

					return 0;

			}



			$this->gmail_data = GMailer::execute_curl(

				GM_LNK_GMAIL."?".$url,

				GM_LNK_GMAIL."?".$refer,

				$method,

				$postdata

			);

			GMailer::parse_gmail_response($this->gmail_data);



			if ($action == "send_verify" or $action == "add" or $action == "add_pre" or $action == "verify_code") {

				$status  = 1;

			} else {

				$status  = (isset($this->raw["cfs"])) ? 1 : 0;

			}



/* 			$status = (isset($this->raw["ar"][1])) ? $this->raw["ar"][1] : 0; */

			$message = (isset($this->raw["ar"][2])) ? $this->raw["ar"][2] : "";



			$a = array(

				"action" 		=> "custom from: $action",

				"status" 		=> (($status) ? "success" : "failed"),

				"message" 		=> $message

			);

			array_unshift($this->return_status, $a);



			return $status;

		} else {

			$a = array(

				"action" 		=> "custom from",

				"status" 		=> "failed",

				"message" 		=> "libgmailer: not connected"

			);

			array_unshift($this->return_status, $a);



			return false;

		}

	}



	/**

	* Parse Gmail responses.

	*

	* @access private

	* @static

	* @return bool 

	* @param string $raw_html

	* @author Neerav

	* @since 27 Nov 2005

	*/

	function at_value() {

		$at_value = "";

		$cc = split(";", $this->cookie_str);

		foreach ($cc as $cc_part) {

			$cc_parts = split("=", $cc_part);

			if (trim($cc_parts[0]) == "GMAIL_AT") {

				$at_value = $cc_parts[1];

				break;

			}

		}

		

		return $at_value;

	}



	/**

	* Parse Gmail responses.

	*

	* @access private

	* @static

	* @return bool 

	* @param string $raw_html

	* @since 7 Jun 2005

	*/

	function parse_gmail_response($raw_html) {

		$raw_html = str_replace("\n", "", $raw_html);

		$raw_html = str_replace("D([", "\nD([", $raw_html);

		$raw_html = str_replace("]);", "]);\n", $raw_html);

		// Fix Gmail's conversion of = and /; by Neerav; 18 Dec 2005

		$raw_html = str_replace(array('u003d','u002f'),array('=','/'),$raw_html);

/* 		$raw_html = preg_replace(array('/(<[^>]*?u003d[^>]*?'.'>)/e'),array('str_replace("u003d","=",\1)'),$raw_html); */

/* 		$raw_html = str_replace(array('\\\\u003d\\\\','\\\\u002f\\\\'),array('=','/'),$raw_html); */

/* 		$raw_html = preg_replace(array('/(<[^>]*?u003d[^>]*?'.'>)/e'),array('str_replace("u003d","=",\1)'),$raw_html); */

/* 		$raw_html = preg_replace('/(\w)u003d\"/','\\1=\\2',&$raw_html); */

/* 		$raw_html = str_replace(array('u003d\"','u002f'),array('=\"','/'),$raw_html); */

/* 		$raw_html = preg_replace(array('/(<[^>]*?)u003d/'),array('\\1='),$raw_html); */

		

		$regexp = "|D\(\[(.*)\]\);|U"; 

		$matches = "";	 

		preg_match_all($regexp, $raw_html, $matches, PREG_SET_ORDER); 

		$packets = array();

		for ($i = 0; $i < count($matches); $i++) {

			$off = 0;

			$tmp = GMailer::parse_data_packet("[".$matches[$i][1]."]", $off);

			if (array_key_exists($tmp[0], $packets) || ($tmp[0]=="mi"||$tmp[0]=="mb"||$tmp[0]=="di")) {

				// Added cl as alternate contact datapack; by Neerav; 15 June 2005

				if ($tmp[0]=="t" || $tmp[0]=="ts" || $tmp[0]=="a" || $tmp[0]=="cl")

					$packets[$tmp[0]] = array_merge($packets[$tmp[0]], array_slice($tmp, 1));

				if ($tmp[0]=="mi" || $tmp[0]=="mb" || $tmp[0]=="di") {

					if (array_key_exists("mg", $packets))

						array_push($packets["mg"],$tmp);

					else

						$packets["mg"] = array($tmp);

				}									  

			} else {

				$packets[$tmp[0]] = $tmp;

			}

		}

		$this->raw = $packets;

		return 1;

	}

}



/**

 * Class GMailSnapshot allows you to read information about Gmail in a structured way.

 * 

 * There is no creator for this class. You must use {@link GMailer::getSnapshot()} to obtain

 * a snapshot.

 *

 * @package GMailer

*/

class GMailSnapshot {

	var $created;



	/**

	* Constructor.

	*

	* Note: you are not supposed to create a GMailSnapshot object yourself. You should

	* use {@link GMailer::getSnapshot()} instead.

	*

	* @return GMailSnapshot

	* @param constant $type

	* @param array $raw

	*/

	function GMailSnapshot($type, $raw, $use_session, $raw_html) {

		// input: raw packet generated by GMailer

		

		// Invalid datapack checking

		// snapshot_error Added; by Neerav;  3 Aug 2005

		// Added http errors; by Neerav; 16 Sept 2005

		if ((!is_array($raw)) or (count($raw) == 0)) {

			$this->created = 0;

		

			if (ereg('gmail_error=([0-9]{3})',$raw_html,$matches)) {

				$this->snapshot_error = $matches[1];

				if ($matches[1] != 500) {

					Debugger::say("libgmailer: Gmail http error (".$matches[1]."), dump RAW HTML:\n".print_r($raw_html,true));

				}

/* 				$this->snapshot_error_no = $matches[1]; */

/* 				ereg('<p><font size="-1">(.*?)</font></p>',$raw_html,$matches); */

/* 				$this->snapshot_error = $matches[1]; */



			} elseif (ereg('<title>([0-9]{3}) Server Error</title>',$raw_html,$matches)) {

				$this->snapshot_error = $matches[1];

				if ($matches[1] != 502) {

					Debugger::say("libgmailer: Gmail http error (".$matches[1]."), dump RAW HTML:\n".print_r($raw_html,true));

				}



			} elseif (strpos($raw_html,'500 Internal Server Error') !== false) {

				$this->snapshot_error = 500;



			} elseif (strpos($raw_html,'gmail_error=') !== false) {

				$this->snapshot_error = "Unknown gmail error";

				Debugger::say("libgmailer: unknown gmail error, dump RAW HTML:\n".print_r($raw_html,true));



			} elseif (strpos($raw_html,'top.location="https://www.google.com/accounts/ServiceLogin') !== false) {

				// Added error; by Neerav; 12 Oct 2005

				//libgmailer: Gmail redirect to login screen

				$this->snapshot_error = "libg110";



			} elseif ($raw_html == "") {

				$this->snapshot_error = "No response from Gmail";



			} elseif (!is_array($raw)) {

				$this->snapshot_error = "Invalid response from Gmail (not an array)";

				Debugger::say("libgmailer: invalid datapack -- not an array, dump RAW HTML:\n".print_r($raw_html,true));



			} elseif (count($raw) == 0) {

				$this->snapshot_error = "Invalid response from Gmail (empty)";



			}



			return null;

		}



		// Gmail version

		if (isset($raw["v"][1])) $this->gmail_ver = $raw["v"][1];

		//$raw["v"][2]	// What is this?  Another version number?

		//$raw["v"][3]	// What is this?



		// IdentificationKey (ik)

		// Added by Neerav; 6 July 2005

		if ($use_session) {

			if (!isset($_SESSION['id_key']) or ($_SESSION['id_key'] == "")) {

				Debugger::say("Snapshot: Using Sessions, saving id_key(ik)...");

				if (isset($raw["ud"][3])) {

					$_SESSION['id_key'] = $raw["ud"][3];

					Debugger::say("Snapshot: Session id_key saved: " . $_SESSION['id_key']);

				} else {

					Debugger::say('Snapshot: Session id_key NOT saved.  $raw["ud"][3] not found.');

				}

			}

		} else {

			if (!isset($_COOKIE[GM_COOKIE_IK_KEY]) or ($_COOKIE[GM_COOKIE_IK_KEY] == 0)) {

				Debugger::say("Snapshot: Using Cookies, saving id_key(ik)...");

				if (isset($raw["ud"][3])) {

					if (strpos($_SERVER["HTTP_HOST"],":"))

						$domain = substr($_SERVER["HTTP_HOST"],0,strpos($_SERVER["HTTP_HOST"],":"));

					else

						$domain = $_SERVER["HTTP_HOST"];

					Debugger::say("Saving id_key as cookie ".GM_COOKIE_IK_KEY." with domain=".$domain);

						

					header("Set-Cookie: ".GM_COOKIE_IK_KEY."=".base64_encode($raw["ud"][3])."; Domain=".$domain.";");

					Debugger::say("Snapshot: Cookie id_key saved: ".GM_COOKIE_IK_KEY."=".base64_encode($raw["ud"][3]));

				} else {

					Debugger::say('Snapshot: Cookie id_key NOT saved.  $raw["ud"][3] not found.');

				}

			}

		}

		

		// other "UD"

		// Added by Neerav; 6 July 2005

		if (isset($raw["ud"])) {

			// account email address

			// your app SHOULD cache this in session or cookie for use across pages

			// Added by Neerav; 6 May 2005

			$this->gmail_email = $raw["ud"][1];

			//$raw["ud"][2]		// keyboard shortcuts

			//$raw["ud"][3]		// Identification Key, set above	

			//$raw["ud"][4]		// What is this?  referrer?

			//$raw["ud"][5]		// What is this?

			//$raw["ud"][6]		// What is this?

			//$raw["ud"][7]		// What is this?

		}

		

		// su

		//$raw["su"][1]		// What is this? (matches $raw["v"][2])	

		//$raw["su"][2]		// What is this? (?? array of text strings for invites)

		

		// cp

		//$raw["cp"][1]		// What is this? (always 1)

		//$raw["cp"][2]		// What is this? (always 0)



		// csm

		//$raw["csm"][1]		// What is this? (always 1)



		// cld

		//$raw["cld"]			// What is this? (empty)



		// COUntry

		// Added by Neerav; 20 Dec 2005

		$this->country = ((isset($raw["cou"][1]))?$raw["cou"][1]:"");



		// Google Accounts' name

		// your app SHOULD cache this in session or cookie for use across pages

		//     it's bandwidth expensive to retrieve preferences just for this

		// Added by Neerav; 2 July 2005

		if (isset($raw["gn"][1])) $this->google_name = $raw["gn"][1];



		// Signature

		// your app SHOULD cache this in session or cookie for use across pages

		//     it's bandwidth expensive to retrieve preferences just for this

		// Added by Neerav; 6 July 2005

		if (isset($raw["p"])) {

			for ($i = 0; $i < count($raw["p"]); $i++) {

				if ($raw["p"][$i][0] == "sx_sg") {

					// can be undefined ?!?!

					$this->signature = (isset($raw["p"][$i][1])) ? $raw["p"][$i][1] : "" ;

					break;	

				}

			}

		}



		

		// Invites

		if (isset($raw["i"][1])) {

			$this->have_invit = $raw["i"][1];

		} else {

			$this->have_invit = 0;

		}



		// QUota information

		if (isset($raw["qu"])) {

			// Space used as xx MB

			$this->quota_mb  = $raw["qu"][1];

			// Total space allotted as xxxx MB

			$this->quota_tot = $raw["qu"][2];	// Added by Neerav; 6 May 2005

			// Space used as xx%

			$this->quota_per = $raw["qu"][3];	// Added by Neerav; 6 May 2005

			// html color as #aabbcc (normally a green color, but red when nearly full)

			$this->quota_col = $raw["qu"][4];	// Added by Neerav; 6 July 2005

		}



		// Footer Tips or Fast Tips

		// Added by Neerav; 6 July 2005

		if (isset($raw["ft"][1])) $this->gmail_tip = $raw["ft"][1];



		// cfs; Compose from source

		// Added by Neerav: 30 Aug 2005; Modified by Gan: 9 Sep 2005

		$this->personality = array();

		$this->personality_unverify = array();

		if (isset($raw["cfs"])) {

			if (isset($raw["cfs"][1])) {

				$person_verified = count($raw["cfs"][1]);

				for($i = 0; $i < $person_verified; $i++) {

					$this->personality[] = array(

						"name"		=> $raw["cfs"][1][$i][0],

						"email"		=> $raw["cfs"][1][$i][1],

						"default"   => (($raw["cfs"][1][$i][2]==0) ? false : true),

						"reply-to"  => ((isset($raw["cfs"][1][$i][3])) ? $raw["cfs"][1][$i][3] : ""), // [not available to everyone yet (Gan: 9 Sept)]

						"verified" 	=> true

					);

				}

				$person_unverified = count($raw["cfs"][2]);

				for($i = 0; $i < $person_unverified; $i++) {

					$this->personality_unverify[] = array(

						"name"		=> $raw["cfs"][2][$i][0],

						"email"		=> $raw["cfs"][2][$i][1],

						"default"   => (($raw["cfs"][2][$i][2]==0) ? false : true),

						"reply-to"  => ((isset($raw["cfs"][2][$i][3])) ? $raw["cfs"][2][$i][3] : ""), // [not available to everyone yet (Gan: 9 Sept)]

						"verified" 	=> false

					);

				}

			}

		}



		// What is this?

		// $raw["df"][1]  // shows ?false?

		// $raw["ms"]

		// $raw["e"]

		// $raw["pod"]

		// $raw["te"]

		// $raw["csm"][1]

		// $raw["ad"] // web clips and advertisements



		if ($type & (GM_STANDARD|GM_LABEL|GM_CONVERSATION|GM_QUERY)) {

			// Added by Neerav; 6 May 2005

			if (isset($raw["p"]) and !isset($this->signature)) {

				for ($i = 1; $i < count($raw["p"]); $i++) {

					if ($raw["p"][$i][0] == "sx_sg") {

						// can be undefined ?!?!

						$this->signature = (isset($raw["p"][$i][1])) ? $raw["p"][$i][1] : "" ;

						break;	

					}

				}

			}

			if (!isset($this->signature)) $this->signature = "";



			// when a conversation does not exist, neither does ds; Fix by Neerav; 1 Aug 2005

			if (isset($raw["ds"])) {

				if (!is_array($raw["ds"])) {

					$this->created = 0;

					$this->snapshot_error = "libgmailer: invalid datapack";

					return null;

				}

				// Fix for change in format of unread messages in some accounts; by Neerav; 2 Feb 2006

				if (is_array($raw["ds"][1])) {

					$this->std_box_new = array(0,0,0,0,0,0,0);

					$std_boxes = array("inbox","starred","sent","drafts","all","spam","trash");

					foreach ($raw["ds"][1] as $std_box) {

						$name = $std_box[0];

						$which_box = array_search($name,$std_boxes);

						if ($which_box !== false and $which_box !== "") {

							$this->std_box_new[$which_box] = $std_box[1];

						}

					}

				} else {

					$this->std_box_new = array_slice($raw["ds"],1);

				}

			} else {

				$this->created = 0;

				if (isset($raw["tf"])) {

					$this->snapshot_error = $raw["tf"][1];

				} else {

					$this->snapshot_error = "libgmailer: unknown but fatal datapack error";

					Debugger::say("ds AND tf undefined, dumping raw: ". print_r($raw,true));

				}

				return null;

			}



			$this->label_list = array();

			$this->label_new = array();



			// Last changed by Neerav; 12 July 2005

			if ((isset($raw["ct"][1])) and (count($raw["ct"][1]) > 0)) {

				foreach ($raw["ct"][1] as $v) {

					array_push($this->label_list, $v[0]);

					array_push($this->label_new, $v[1]);

				}			 

			} elseif (isset($raw["ct"]) and !isset($raw["ct"][1])) {

				Debugger::say('ct[1] not set, raw[ct] dump: '.print_r($raw["ct"],true));

			} 

									

			// Thread Summary

			if (isset($raw["ts"])) {

				$this->view 	 = (GM_STANDARD|GM_LABEL|GM_QUERY);

				$this->box_name  = $raw["ts"][5];		// name of box/label/query

				$this->box_total = $raw["ts"][3];		// total messages found

				$this->box_pos 	 = $raw["ts"][1];		// starting message number



				// Added by Neerav; 6 July 2005

				$this->box_display 		= $raw["ts"][2];	// max number of messages to display on the page

				$this->box_query 		= $raw["ts"][6];	// gmail query for box

				$this->queried_results 	= $raw["ts"][4];	// was this a search query (bool)

				//$this->?? 		= $raw["ts"][7];		// what is this?? some id number?

				//$this->?? 		= $raw["ts"][8];		// what is this?? total number of messages in account?

				//$this->?? 		= $raw["ts"][9];		// what is this?? serial number, id number, VERY LONG!

				//$this->?? 		= $raw["ts"][10];		// what is this?? always blank

			}



			$this->box = array();

			if (isset($raw["t"])) {					  

				foreach ($raw["t"] as $t) {

					if ($t == "t") continue;

					

					// Fix for 12 OR 13 fields!!; by Neerav; 23 July 2005

					//$less  = (count($t) == 12) ? 1 : 0 ;

					// Changed to 12 or 13 vs. 14 fields; by Neerav; 25 Oct 2005

					// is this permanent??  did Gmail increase the size of the array?? Why?  What?

					//$less  = (count($t) == 12 or count($t) == 13) ? 1 : 0 ;



					// Gmail increased the length of the array on/before 25 Oct 2005

					// Instead of relying on array size, we look for the labels array

					// Update: (15 Apr 2006) now there are upto 16 fields.

					if (count($t) < 12) {

						$less = 0;

						

						$tb["id"]		= $t[0];

						$tb["is_read"]	= 0;

						$tb["is_starred"]= 0;

						$tb["date"]		= "(error)";

						$tb["sender"]	= "(error)";

						$tb["flag"]		= "";

						$tb["subj"]		= "(error)";

						//$tb["snippet"]	= ((count($t) == 12) ? "" : $t[7] );

						$tb["snippet"]	= "(error)";

						$tb["msgid"]	= "(error)";

						$tb["labels"]	= array();	// gives an array even if 0 labels

						$tb["attachment"]= array();

						//$tb["??"]		= $t[10-$less];	

						//$tb["??"]		= $t[11-$less];

						$tb["long_date"]	= "(error)";

						$tb["long_time"]	= "(error)";

						$tb["is_chat"]		= 0;

						$tb["chat_length"]	= "";

						//$tb["??"]		= $t[15-$less];

						array_push($this->box, $tb);

						continue;

					

					} elseif (is_array($t[8])) {

						// normal

						$less = 0;

					} elseif (is_array($t[7])) {

						// without snippet

						$less = 1;

					} elseif (is_array($t[9])) {

						// just here for future compatibility

						$less = -1;

					} elseif (is_array($t[6])) {

						// just here for future compatibility

						$less = 2;

					} else {

						$less = 0;

					}

					

					

					// Added by Neerav; 6 July 2005

					$long_date = "";

					$long_time = "";

					$date_time = explode("_",$t[12-$less]);

					if (isset($date_time[0])) $long_date = $date_time[0];

					if (isset($date_time[1])) $long_time = $date_time[1]; 

											

					// Added labels for use in multiple languages; by Neerav; 7 Aug 2005

					//$label_array_lang = $t[8-$less];	



					// Added by Neerav; 6 July 2005

					// Gives an array of labels and substitutes the standard names

					// Changed to be language compatible; by Neerav; 8 Aug 2005

					$label_array = array();

					foreach($t[8-$less] as $label_entry) {

						switch ($label_entry) {

							//case "^i": 	$label_array[] = "Inbox";		break;

							//case "^s": 	$label_array[] = "Spam";		break;

							//case "^k": 	$label_array[] = "Trash";		break;

							case "^t": 	/* Starred */					break;

							//case "^r": 	$label_array[] = "Draft";		break;

							default:	$label_array[] = $label_entry; 	break;

						}

					}



					$tb = array();

					$tb["id"]		= $t[0];

					$tb["is_read"]	= (($t[1] == 1) ? 1 : 0);

					$tb["is_starred"]= (($t[2] == 1) ? 1 : 0);

					$tb["date"]		= strip_tags($t[3]);

					$tb["sender"]	= strip_tags($t[4],"<b>");

					$tb["flag"]		= $t[5];

					$tb["subj"]		= strip_tags($t[6],"<b>");

					//$tb["snippet"]	= ((count($t) == 12) ? "" : $t[7] );

					$tb["snippet"]	= (($less) ? "" : $t[7] );

					$tb["msgid"]		= $t[10-$less];



					// Added by Neerav; 7 Aug 2005

					//$tb["labels_lang"]= $label_array_lang;	// for use with languages

					// Added/Changed by Neerav; 6 July 2005

					$tb["labels"]	= $label_array;	// gives an array even if 0 labels

					$tb["attachment"]= ((strlen($t[9-$less]) == 0) ? array() : explode(",",$t[9-$less]));// Changed to give an array even if 0 attachments

					//$tb["??"]		= $t[10-$less];		// what is this?? repeat of id??

					//$tb["??"]		= $t[11-$less];			// what is this?? always 0

					$tb["long_date"]	= $long_date;		// added

					$tb["long_time"]	= $long_time;		// added

					// some accounts have chat, some do not

					if (isset($t[13-$less])) {

						$tb["is_chat"]		= $t[13-$less];		// Added by (Gmail) Neerav; 16 Feb 2006;

						$tb["chat_length"]	= $t[14-$less];		// Added by (Gmail) Neerav; 16 Feb 2006;

						//$tb["??"]		= $t[15-$less];			// Added by (Gmail) Neerav; 16 Feb 2006; what is this?? always 0

					} else {

						$tb["is_chat"]		= 0;			// Added by (Gmail) Neerav; 16 Feb 2006;

						$tb["chat_length"]	= "";			// Added by (Gmail) Neerav; 16 Feb 2006;

						//$tb["??"]		= $t[15-$less];		// Added by (Gmail) Neerav; 16 Feb 2006; what is this?? always 0

					}



					array_push($this->box, $tb);

				}

			}

			if (isset($raw["cs"])) {

				//Debugger::say("cs exists: ".print_r($raw["cs"],true));

				//Debugger::say("cs exists, dumping raw: ".print_r($raw,true));



				// Fix for 14 OR 12 fields!!; by Neerav; 25 July 2005

				$less  = (count($raw["cs"]) == 12) ? 2 : 0 ;



				$this->view = GM_CONVERSATION;				

				$this->conv_id = $raw["cs"][1];

				$this->conv_title = $raw["cs"][2];

				// $raw["cs"][3]		// what is this??  escape/html version of 2?

				// $raw["cs"][4]		// what is this?? empty

				// $raw["cs"][5]		// (array) conversation labels, below

				// $raw["cs"][6]		// what is this?? array

				// $raw["cs"][7]		// what is this?? integer/bool?

				$this->conv_total = $raw["cs"][8];

				// (count($t) == 14) $raw["cs"][9] 	// may be missing! what is this?? long id number?

				// (count($t) == 14) $raw["cs"][10]	// may be missing! what is this?? empty

				// $raw["cs"][11-$less]		// may be 9 what is this?? repeat of id 1?

				// $raw["cs"][12-$less]		// may be 10 what is this?? array

				// $raw["cs"][13-$less]		// may be 11 what is this?? integer/bool?



				$this->conv_labels = array ();

				$this->conv_starred = false;



				// Added labels for use in multiple languages; by Neerav; 7 Aug 2005

				//$this->conv_labels_lang = $raw["cs"][5];	// for use with languages



				// Changed to give translated label names; by Neerav; 6 July 2005

				// Changed back to be language compatible; by Neerav; 8 Aug 2005

				//$this->conv_labels_temp = (count($raw["cs"][5])==0) ? array() : $raw["cs"][5];	

				$temp_array = $raw["cs"][5];

				foreach($raw["cs"][5] as $label_entry) {

					switch ($label_entry) {

						//case "^i": 	$this->conv_labels[] = "Inbox";		break;

						//case "^s": 	$this->conv_labels[] = "Spam";		break;

						//case "^k": 	$this->conv_labels[] = "Trash";		break;

						case "^t": 	$this->conv_starred  = true;		break;

						//case "^r": 	$this->conv_labels[] = "Draft";		break;

						default:	$this->conv_labels[] = $label_entry; break;

					}

				}

				

				$this->conv = array();

							 

				if (!isset($raw["mg"])) {

					// Added error; by Neerav; 24 Sept 2005

					// libg102 error: a specific message has been requested, but must actually be 

					// taken from the thread (message may be a draft or other expanded message)

					$this->snapshot_error = "libg102"; 

					$this->created = 0;

					return null;

				} else {

					$mg_count = count($raw["mg"]);

					for ($i = 0; $i < $mg_count; $i++) {

						if ($raw["mg"][$i][0] == "mb" && $i > 0) {

							if (isset($raw["mg"][$i][1])) {

								$b["body"] .= $raw["mg"][$i][1];

							} else {

								// Added error; by Neerav; 9 Feb 2006

								// THIS ERROR OCCURS BECAUSE ??

								$this->snapshot_error = "libg101";

								$this->created = 0;

								return null;

							}

							if (isset($raw["mg"][$i][2])) {

								if ($raw["mg"][$i][2] == 0) {

									array_push($this->conv, $b);

									unset($b);

								}

							} else {

								// Added error; by Neerav; 9 Feb 2006

								// THIS ERROR OCCURS BECAUSE OF IMPROPER DATAPACK PARSING

								$this->snapshot_error = "libg101";

								$this->created = 0;

								return null;

							}

						} elseif (($raw["mg"][$i][0] == "mi") or ($raw["mg"][$i][0] == "di")) {

							// to account for an added 20th index with a phishing warning

							// Added by Neerav; 1 Dec 2005

/* 							$more  = (isset($raw["mg"][$i][26]) and is_array($raw["mg"][$i][26])) ? 1 : 0 ; */

							// Changed by Neerav; 24 Mar 2006

							$more  = (isset($raw["mg"][$i][20]) and strpos($raw["mg"][$i][20],"<font color=\"#ffffff\">") !== false) ? 1 : 0 ;

							

							// Changed to merge "di" and "mi" routines; by Neerav; 11 July 2005

							if (isset($b)) {

								array_push($this->conv, $b);

								unset($b);

							}

							$b = array();

							// $raw["mg"][$i][0] is mi or di

							$b["mbox"] 			= $raw["mg"][$i][1];	// Added by Neerav; 11 July 2005

							$b["is_trashed"]	= ((int)$raw["mg"][$i][1] & 128) 	? true : false;	// Added by Neerav; 23 Feb 2006

							$b["is_html"]		= ((int)$raw["mg"][$i][1] &(16|32))	? true : false;	// Added by Neerav; 23 Feb 2006

							$b["html_images"] 	= ((int)$raw["mg"][$i][1] & 32) 	? true : false;	// Added by Neerav; 23 Feb 2006

							$b["index"] 		= $raw["mg"][$i][2];

							$b["id"] 			= $raw["mg"][$i][3];

							$b["is_star"] 		= $raw["mg"][$i][4];

							if ($b["is_star"] == 1) $this->conv_starred = true;

							$b["draft_parent"] 	= $raw["mg"][$i][5];  	// was only defined in draft, now both; Changed by Neerav; 11 July 2005

							$b["sender"] 		= $raw["mg"][$i][6];

							$b["sender_short"]	= $raw["mg"][$i][7];	// Added by Neerav; 11 July 2005

							$b["sender_email"] 	= str_replace("\"", "", $raw["mg"][$i][8]);		// remove annoying d-quotes in address

							$b["recv"] 			= strip_tags($raw["mg"][$i][9]);

							$b["recv_email"] 	= str_replace("\"", "", $raw["mg"][$i][11]);

							$b["cc_email"] 		= str_replace("\"", "", $raw["mg"][$i][12]);	// was only defined in draft, now both; Changed by Neerav; 11 July 

							$b["dt_easy"] 		= $raw["mg"][$i][10];

							if (	isset($raw["mg"][$i][15]) 

								and isset($raw["mg"][$i][16])

								and isset($raw["mg"][$i][13])

								and isset($raw["mg"][$i][14])

								and isset($raw["mg"][$i][17])

								) {

								$b["bcc_email"] 	= str_replace("\"", "", $raw["mg"][$i][13]);	// was only defined in draft, now both; Changed by Neerav; 11 July 2005							

								$b["reply_email"] 	= str_replace("\"", "", $raw["mg"][$i][14]);

								$b["dt"] 			= $raw["mg"][$i][15];

								$b["subj"] 			= $raw["mg"][$i][16];

							} else {

								// Added error; by Neerav; 9 Jan 2006

								// THIS ERROR OCCURS BECAUSE OF IMPROPER DATAPACK PARSING

								$this->snapshot_error = "libg101";

								$this->created = 0;

								return null;

							}

							$b["snippet"] 			= $raw["mg"][$i][17];

							$b["sender_in_contact"] = $raw["mg"][$i][19];	// (0,1) sender already in the contacts list; Added by Neerav; 6 Mar 2006

							$b["attachment"] 		= array();

							if (isset($raw["mg"][$i][18])) {	// attachments

								if (!is_array($raw["mg"][$i][18])) {

									// Added error; by Neerav; 24 Sept 2005

									// THIS ERROR OCCURS BECAUSE OF IMPROPER DATAPACK PARSING

									$this->snapshot_error = "libg101";

									$this->created = 0;

									return null;

								} else {

									foreach ($raw["mg"][$i][18] as $bb) {

										array_push(

											$b["attachment"], 

											array("id"		=> $bb[0],

												"filename"	=> $bb[1],

												"type"		=> str_replace("\"", "", $bb[2]),	 // updated to remove the "'s; by Neerav; 19 Jan 2006

												"size"		=> $bb[3]

												//,""		=> $bb[4]	// always -1, what is this?? 

												//,""		=> $bb[5]	// repeat of [0]?, what is this?? 

												)

										);

										if (!isset($bb[1])) {

											Debugger::say("undefined attachment info, dumping message: ", print_r($raw["mg"][$i],true));

											Debugger::say("undefined attachment info, dumping raw: ".print_r($raw,true));

											Debugger::say("undefined attachment info, dumping raw_html: ".print_r($raw_html,true));

										}

									}

								}

							}

							if ($raw["mg"][$i][0] == "mi") {

								$b["is_draft"] 		= false;

								$b["body"] 			= "";

								$b["warning"]		= (($more == 1) ? $raw["mg"][$i][20]: "");		// phishing WARNING from Gmail  // Added by Neerav; 1 Dec 2005

								// $raw["mg"][$i][20+$more];  // ?? repeated date in unix-like format with an _ // Added by Neerav; 11 July 2005

								$b["quote_str"] 	= $raw["mg"][$i][21+$more];

								$b["quote_str_html"]= $raw["mg"][$i][22+$more];



								// Added the following indexes; Neerav; 1 Dec 2005

								// $raw["mg"][$i][23+$more];  // What is this?? sender's domain?

								// $raw["mg"][$i][24+$more];  // always blank What is this??

								// $raw["mg"][$i][25+$more];  // always array(,,1) What is this??

								// $raw["mg"][$i][26+$more];  // always blank What is this??

								// $raw["mg"][$i][27+$more];  // array(,,0) or blank What is this??

								// $raw["mg"][$i][28+$more];  // always 0 What is this??

								// $raw["mg"][$i][29+$more];  // header: Sender (real sender: don't need this) // 6 Mar 2006

								// $raw["mg"][$i][30+$more];  // header: Message-ID (don't need this in snapshot)  // 3 Mar 2006

								// $raw["mg"][$i][31+$more];  // always 0 What is this??

								$b["to_custom_from"] = (isset($raw["mg"][$i][32+$more])?$raw["mg"][$i][32+$more]:"");  // Custom From which this message was sent to

								// $raw["mg"][$i][33+$more];  // always 0 What is this??

								

							} elseif ($raw["mg"][$i][0] == "di") {

								$b["is_draft"] 		= true;

								$b["body"] 			= $raw["mg"][$i][20];

								// $raw["mg"][$i][21];  // ?? repeated date slightly different format  // Added by Neerav; 11 July 2005

								if (isset($raw["mg"][$i][22]) and isset($raw["mg"][$i][23])) {

									$b["quote_str"] 	= $raw["mg"][$i][22];

									$b["quote_str_html"]= $raw["mg"][$i][23];

								} else {

									// Added error; by Neerav; 9 Jan 2006

									// THIS ERROR OCCURS BECAUSE OF IMPROPER DATAPACK PARSING

									$this->snapshot_error = "libg101";

									$this->created = 0;

									return null;

								}							



								// Added to match additions to "mi"; by Neerav; 1 Dec 2005

								$b["warning"] 		= "";

							}

						}

					}

				}

				if (isset($b)) array_push($this->conv, $b);

			}

		}

		

		// Changed from elseif to if; by Neerav; 5 Aug 2005

		if  ($type & GM_CONTACT) {

			$this->contacts = array();

			$this->contact_groups = array();	// Added by Neerav; 20 Dec 2005

			$this->contacts_total = 0;			// Added by Neerav; 5 Jan 2006

						

			// general contacts information; Added by Neerav; 5 Jan 2006

			if (isset($raw["cls"])) {

				$this->contacts_total = $raw["cls"][1];		// total number of contacts

				//$raw["cls"][2]							// array, type of contacts

					//$raw["cls"][2][i][0]					// Gmail code for type of contacts: p=frequent, a=all, l=group, s=search

					//$raw["cls"][2][i][1]					// Human readable button text for the above code type

				$this->contacts_shown = $raw["cls"][3];		// Gmail code for type of contacts currently shown/retrieved

				//$this->contacts_total = $raw["cls"][4]	// is 4 ?? What is this??

			}

			

			// Added by Neerav; 29 June 2005

			// Since gmail changes their Contacts array often, we need to see which

			//    latest flavor (or flavour) they are using!

			// Some accounts use "a" for both lists and details

			// 	  whereas some accounts use "cl" for lists and "cov" for details

			$type = "";

			$c_grp_det = "";

			if (isset($raw["a"])) {

				Debugger::say("uses 'a' for contacts: ".print_r($raw,true));

				$c_array = "a";

				// determine is this is a list or contact detail

				if ((count($raw["a"]) == 2) and isset($raw["a"][1][6])) {

					$type 		= "detail";

					$c_id 		= 0;

					$c_name 	= 1;

					$c_email 	= 3;

					$c_groups	= 4;

					$c_notes 	= 5;

					$c_detail 	= 6;

				} else {

					$c_email 	= 3;

					$c_notes 	= 4;

					$type 		= "list";

					//$c_addresses 	= 5;

				}

			} elseif (isset($raw["cl"])) {	// list

				$c_array 		= "cl";

				$c_email 		= 4;

				$c_notes 		= 5;

				$c_addresses 	= 6;

				$type 			= "list";

			} elseif (isset($raw["cov"])) {	// contact detail in accounts using "cl"

				$c_array 		= "cov";

				$type 			= "detail";

				$c_id 			= 1;

				$c_name 		= 2;

				$c_email 		= 4;

				$c_groups		= 6;

				$c_notes 		= 7;

				$c_detail 		= 8;

			} elseif (isset($raw["clv"])) {	// group detail in accounts using "cl" // added by Neerav; 6 Jan 2006

				$c_array 		= "clv";

				//$c_grp_det		= "cle";

				$type 			= "detail";

				$c_id 			= 1;

				$c_name 		= 2;

				$c_email 		= 6;

				$c_total 		= 3;

				$c_detail 		= 5;

				$c_members		= 4;

				$c_notes		= 0;

			} else {

				array_push(

					$this->contacts, 

					array("id" 	 => "error",

						 "name"  => "libgmailer Error",

						 "email" => "libgmailer@error.nonexistant",

						 "is_group" => 0,

						 "notes" => "libgmailer could not find the Contacts information "

						 	. "due to a change in the email service (again!).  Please contact " 

						 	. "the author of this program (which uses libgmailer) for a fix."

					)

				);

			}



			// Changed by Neerav; 

			// from "a" to "cl" 15 June 2005

			// from "cl" to whichever exists 29 June 2005

			if ($type == "list") {

				// An ordinary list of contacts

				for ($i = 1; $i < count($raw["$c_array"]); $i++) {

					$a = $raw["$c_array"][$i];

					$b = array(

						"id"	=> $a[1],				// contact id; Added by Neerav; 6 May 2005

						"name"	=> (isset($a[2])?$a[2]:""),

						"email"	=> str_replace("\"", "", $a[$c_email])	// Last Changed by Neerav; 29 June 2005

					);

					// Last Changed by Neerav; 29 June 2005

					if (isset($a[$c_notes])) {

						// Contact groups support; 5 Jan 2006

						if (is_array($a[$c_notes])) {

							$b["notes"] = "";

							$b["is_group"] = true;

							// email addresses for groups are in a different location and format

							// "Name" <email@address.net>, "Name2" <email2@address.net>, etc

							// and needs to be "simply" re-created for backwards compatibility

							$gr_count = count($a[$c_notes]);

							$group_addresses = array();

							for ($gr_entry = 0; $gr_entry < $gr_count; $gr_entry++) {

								$group_addresses[] = $a[$c_notes][$gr_entry][1];

							}

							$b["email"]	= implode(", ",$group_addresses);

							

							//$b["email"]	= str_replace("\"", "", $a[$c_addresses]);

							$b["group_names"] = $a[$c_email];

							$b["group_total"] = $a[3];

							$b["group_email"] = (count($a[$c_notes]) > 0) ? $a[$c_addresses] : array();

						} else {

							$b["notes"] = $a[$c_notes];

							$b["is_group"] = false;

							$b["groups"] = $a[$c_addresses];

						}

					}

					array_push($this->contacts, $b);

				}

			} elseif ($type == "detail") {

				//Debugger::say("raw: ".print_r($raw,true));

				$details = array();

				if ($c_array == "clv") {

					// Added by Neerav; 6 Jan 2006

					// Group details

					$cov["is_group"]	= true;								// is this a group?

					$cov["id"]			= $raw["$c_array"][1][$c_id];		// group id

					$cov["name"] 		= $raw["$c_array"][1][$c_name];		// group name

					$gr_count = count($raw["$c_array"][1][$c_detail]);

					$cov["group_names"] = $raw["$c_array"][1][$c_members];	// string of names of group members

					$cov["group_total"] = $raw["$c_array"][1][$c_total];	// string, total number of members in group

					$cov["group_email"] = str_replace("\"", "", $raw["$c_array"][1][$c_email]);	// formatted list of addresses as: Name <address>

					$cov["notes"] 		= "";								// no notes for groups... yet!

					$group_addresses = array();								// string of flattened email addresses

					$group_members = array();								// array of group members

					for ($gr_entry = 0; $gr_entry < $gr_count; $gr_entry++) {

						$group_addresses[] = $raw["$c_array"][1][$c_detail][$gr_entry][1];

						$cov["members"][] = array(

							"id"	=>	$raw["$c_array"][1][$c_detail][$gr_entry][0],

							"name"	=>	(isset($raw["$c_array"][1][$c_detail][$gr_entry][2])?$raw["$c_array"][1][$c_detail][$gr_entry][2]:""),

							"email"	=>	$raw["$c_array"][1][$c_detail][$gr_entry][1]

						);

					}

					$cov["email"] = (count($group_addresses) > 0) ? implode(", ",$group_addresses) : "";



					

				} else {

					// Added by Neerav; 1 July 2005

					// Contact details (advanced contact information)

					// used when a contact id was supplied for retrieval

					$cov = array();

					$cov["is_group"]= false;

					$cov["id"]		= $raw["$c_array"][1][$c_id];

					$cov["name"] 	= $raw["$c_array"][1][$c_name];

					$cov["email"] 	= str_replace("\"", "", $raw["$c_array"][1][$c_email]);

					$cov["groups"]	= $raw["$c_array"][1][$c_groups];

					if (isset($raw["$c_array"][1][$c_notes][0])) {

						$cov["notes"] = ($raw["$c_array"][1][$c_notes][0] == "n") ? $raw["$c_array"][1][$c_notes][1] : "";

					} else {

						$cov["notes"] = "";

					}

					$num_details = count($raw["$c_array"][1][$c_detail]);

					if ($num_details > 0) {

						for ($i = 0; $i < $num_details; $i++) {

							$details[$i][] = array(

									"type"	=> "detail_name",

									"info" 	=> $raw["$c_array"][1][$c_detail][$i][0]

							);

							if (isset($raw["$c_array"][1][$c_detail][$i][1])) {

								$temp = $raw["$c_array"][1][$c_detail][$i][1];

							} else {

								$temp = array();

								Debugger::say('$raw['.$c_array.'][1]['.$c_detail.']['.$i.'][1] not defined libgmailer: 2548, dumping raw: '. print_r($raw,true));

							}

							for ($j = 0; $j < count($temp); $j += 2) {

								switch ($temp[$j]) {

									case "p": $field = "phone";		break;

									case "e": $field = "email";		break;

									case "m": $field = "mobile";	break;

									case "f": $field = "fax";		break;

									case "b": $field = "pager";		break;

									case "i": $field = "im";		break;

									case "d": $field = "company";	break;

									case "t": $field = "position";	break;	// t = title

									case "o": $field = "other";		break;

									case "a": $field = "address";	break;

									default:  $field = $temp[$j];	break;	// default to the field type

								}

								$details[$i][] = array(

										"type" => $field, 

										"info" => $temp[$j+1]

								);

							}

						}

					}

					$cov["details"] = $details;

				}



				array_push($this->contacts, $cov);

			}

			

			// Contact groups

			// Added by Neerav; 20 Dec 2005

			if (isset($raw["cla"])) {

				for ($i = 1; $i < count($raw["cla"][1]); $i++) {

					$a = $raw["cla"][1][$i];

					$b = array(

						"id"		=> $a[0],

						"name"		=> $a[1],

						"addresses"	=> ((isset($a[2])) ? str_replace("\"", "", $a[2]) : "")

					);

					array_push($this->contact_groups, $b);

				}

			}



			$this->view = GM_CONTACT;



		}

		

		// Changed from elseif to if; by Neerav; 5 Aug 2005

		if ($type & (GM_PREFERENCE)) {			

			// go to Preference Panel

			// Added by Neerav; 6 July 2005

			if (isset($raw["pp"][1])) {

				switch ($raw["pp"][1]) {

					case "g": 	$this->goto_pref_panel = "general";		break;

					case "l": 	$this->goto_pref_panel = "labels";		break;

					case "f": 	$this->goto_pref_panel = "filters";		break;

					default:	$this->goto_pref_panel = $raw["pp"][1];	break;

				}

			}



			// SETTINGS (NON-Filters, NON-Labels)

			// Added by Neerav; 29 Jun 2005

			

			$this->setting_gen = array();

			$this->setting_fpop = array();

			$this->setting_other = array();

			$this->setting_mobile = array();

			$this->setting_chat = array();



			if (isset($raw["p"])) {

				// GENERAL SETTINGS

				$gen = array(

					//"use_cust_name" => 0,

					"name_google" 	=> ((isset($raw["gn"][1])) ? $raw["gn"][1] : ""),

					//"name_display" 	=> "",

					//"use_reply_to"	=> 0,

					//"reply_to" 		=> "",

					"language" 			=> "en",

					"page_size" 		=> 25,

					"shortcuts" 		=> 0,

					"p_indicator" 		=> 0,

					"show_snippets" 	=> 0,

					"use_signature"		=> 0,

					"signature" 		=> "",

					"encoding"			=> 0,

					"vacation_enabled" 	=> 0,

					"vacation_subject"	=> "",

					"vacation_message"	=> "",

					"vacation_contact"	=> 0,

				);

	

				// FORWARDING AND POP

				$fpop = array(

					"forward"		=> 0,

					"forward_to" 	=> "",

					"forward_action"=> "selected",

					"pop_enabled" 	=> 0,

					"pop_action" 	=> 0

				);

	

				// MOBILE

				$mobile = array(

					"display_boxes"		=> array("inbox","starred","sent","drafts","all","spam","trash")

				);



				// CHAT

				$chat = array(

					"save_chat"				=> 0		// added by Neerav; 10 Feb 2006

				);



				// OTHER

				$other = array(

					"google_display_name"	=> (isset($raw["gn"][1])?$raw["gn"][1]:""),

					"google_reply_to" 		=> "",

					"expand_labels"			=> 1,

					"expand_invites" 		=> 1,

					"expand_talk"	 		=> 1,

					"reply_from_sent"		=> 0,

					"rich_text" 			=> 0,		// not used yet or has been removed

					"save_chat"				=> 0		// added by Neerav; 10 Feb 2006

				);

	

				if (isset($raw["gn"][1])) {

					$gen["name_google"] = $raw["gn"][1];

				}

				

				for ($i = 1; $i < count($raw["p"]); $i++) {

					$pref = $raw["p"][$i][0];

					$value = (isset($raw["p"][$i][1])) ? $raw["p"][$i][1] : "";



					switch ($pref) {

					// GENERAL SETTINGS

						//case "sx_dn":	$gen["name_display"] = $value;		break;	// (string) name on outgoing mail (display name)

						//case "sx_rt":	$gen["reply_to"] = $value;			break;	// (string) reply to email address

						case "sx_dl":	$gen["language"] = $value;			break;	// (string) display language

						case "ix_nt":	$gen["page_size"] = $value;			break;	// (integer) msgs per page (maximum page size)

						case "bx_hs":	$gen["shortcuts"] = $value;			break;	// (boolean) keyboard shortcuts {0 = off, 1 = on}

						case "bx_sc":	$gen["p_indicator"] = $value;		break;	// (boolean) personal level indicators {0 = no indicators, 1 = show indicators}

						case "bx_ns":	$gen["show_snippets"] = !$value;	break;	// (boolean) no snippets {0 = show snippets, 1 = no snippets}

																					// 		we INVERSE this for convenience

						case "sx_sg":	$gen["signature"] = $value;			break;	// (string) signature

						case "bx_en":	$gen["encoding"] = $value;			break;	// (boolean) outgoing message encoding {0 = default, 1 = utf-8}

						// added by Neerav; 20 Dec 2005

						case "bx_ve":	$gen["vacation_enabled"] = $value;	break;	// (boolean) vacation message enabled {0 = OFF, 1 = ON}

						case "sx_vs":	$gen["vacation_subject"] = $value;	break;	// (string) vacation message subject

						case "sx_vm":	$gen["vacation_message"] = $value;	break;	// (string) vacation message text

						case "bx_vc":	$gen["vacation_contact"] = (($value == "true" or $value === true) ? true : false);	break;	// (string to boolean) vacation message, send only to contacts list 

					// FORWARDING AND POP

						case "sx_em":	$fpop["forward_to"] = $value;		break;	// (string) forward to email

						case "sx_at":	$fpop["forward_action"] = $value;	break;	// (string) forwarding action {selected (keep), archive, trash}

						case "bx_pe":	$fpop["pop_enabled"] = $value;		break;	// (integer) pop enabled {0 = disabled, 2 = enabled from now, 3 = enable all}

						case "ix_pd":	$fpop["pop_action"] = $value;		break;	// (integer) action after pop access {0 = keep, 1 = archive, 2 = trash}

					// SIDE BOXES

						case "bx_show0": $other["expand_labels"] = $value;	break;	// (boolean) labels box {0 = collapsed, 1 = expanded}

						case "bx_show1": $other["expand_invites"] = $value;	break;	// (boolean) invite box {0 = collapsed, 1 = expanded}

						case "bx_show3": $other["expand_talk"] = $value;	break;	// (boolean) gtalk box {0 = collapsed, 1 = expanded}

					// ACCOUNT

						case "bx_rf": 	$other["reply_from_sent"] = $value;	

										break;	// (boolean) use reply from [sent] {0 = use default address, 1 = use address message was sent to}

						// added by Neerav; 4 Mar 2006

						case "sx_dn": 	$other["google_display_name"] = $value;	

										break;	// (string) Google accounts "from" display name

						case "sx_rt": 	$other["google_reply_to"] = $value;	

										break;	// (string) Google accounts "from" reply-to address

						// Chat

						// added by Neerav; 10 Feb 2006

						case "ix_ca": 	$chat["save_chat"] = $value;		

										$other["save_chat"] = $value;

										break;	// (boolean) save chat archive {0 = off, 1 = on}

						// added by Neerav; 26 Feb 2006

						case "ix_ql": 	$chat["ix_ql"] = $value;			break;	// (integer)

						case "bx_aa": 	$chat["bx_aa"] = $value;			break;	// (boolean)

						case "bx_lq": 	$chat["bx_lq"] = $value;			break;	// (boolean)

					// MOBILE

						// added by Neerav; 20 Dec 2005

						case "sx_pf": 	if ($value != "") {

											$mobile = array();

											$temp_mobile = explode('#,~',$value);

											for ($mob = 0; $mob < count($temp_mobile); $mob++) {

												if ($temp_mobile[$mob] != "") $mobile['display_boxes'][] = $temp_mobile[$mob];

											}

										}

																			break;

					// OTHER

						// 		not used yet or has been removed from Gmail

						case "bx_cm":	$other["rich_text"] = $value;		break;	// (boolean) rich text composition {0 = plain text, 1 = rich text}

						// added by Neerav; 20 Dec 2005

						//case "bx_aa":	$other["unknown"] = $value;			break;	// 

																					

						default:		$other["$pref"] = $value;			break;

					}

				}

			

				// set useful implicit boolean settings

				//if ($gen["name_display"] != "") $gen["use_cust_name"] = 1;

				//if ($gen["reply_to"] != "") 	$gen["use_reply_to"]  = 1;

				if ($gen["signature"] != "") 	$gen["use_signature"] = 1;

				if ($fpop["forward_to"] != "")  $fpop["forward"] 	  = 1;



				$this->setting_gen 		= $gen;

				$this->setting_fpop 	= $fpop;

				$this->setting_other 	= $other;

				$this->setting_mobile 	= $mobile;

				$this->setting_chat 	= $chat;

			}



			// LABELS

			$this->label_list = array();

			$this->label_total = array();

			if (isset($raw["cta"][1])) {

				foreach ($raw["cta"][1] as $v) {

					array_push($this->label_list, $v[0]);

					array_push($this->label_total, $v[1]);

				}

			} elseif (isset($raw["cta"])) {

				Debugger::say('cta[1] not set, printing cta: '.print_r($raw["cta"],true));

			}

			

			// FILTERS

			$this->filter = array();

			if (isset($raw["fi"][1])) {

				foreach ($raw["fi"][1] as $fi) {

					// Changed/Added by Neerav; 23 Jun 2005

					// filter rules/settings

					//     (The "() ? :" notation is used because empty/false fields at the end of an

					//         array are not always defined)

					$b = array(

						// (integer) filter id number

						"id" 		=> 					 	$fi[0],

						// (string) gmail's filter summary

						"query" 	=> ((isset($fi[1]))    ? $fi[1] : ""),						

						// (string) from field has...

						"from" 		=> ((isset($fi[2][0])) ? $fi[2][0] : ""),

						// (string) to field has...

						"to" 		=> ((isset($fi[2][1])) ? $fi[2][1] : ""),

						// (string) subject has...

						"subject" 	=> ((isset($fi[2][2])) ? $fi[2][2] : ""),

						// (string) msg has the words...

						"has" 		=> ((isset($fi[2][3])) ? $fi[2][3] : ""),

						// (string) msg doesn't have the words...

						"hasnot" 	=> ((isset($fi[2][4])) ? $fi[2][4] : ""),

						// (boolean) has an attachment

						"hasattach" => ((isset($fi[2][5]) and ($fi[2][5] == "true" or $fi[2][5] === true)) ? true : false),

						// (boolean) archive (skip the inbox)

						"archive" 	=> ((isset($fi[2][6]) and ($fi[2][6] == "true" or $fi[2][6] === true)) ? true : false),	

						// (boolean) apply star

						"star" 		=> ((isset($fi[2][7]) and ($fi[2][7] == "true" or $fi[2][7] === true)) ? true : false),

						// (boolean) apply label

						"label" 	=> ((isset($fi[2][8]) and ($fi[2][8] == "true" or $fi[2][8] === true)) ? true : false),

						// (string) label name to apply

						"label_name"=> ((isset($fi[2][9])) ? $fi[2][9] : ""),

						// (boolean) forward

						"forward" 	=> ((isset($fi[2][10]) and ($fi[2][10] == "true" or $fi[2][10] === true)) ? true : false),

						// (string email) forward to email address

						"forwardto" => ((isset($fi[2][11])) ? $fi[2][11]: ""),

						// (boolean) trash the message

						"trash" 	=> ((isset($fi[2][12]) and ($fi[2][12] == "true" or $fi[2][12] === true)) ? true : false)

					);

					array_push($this->filter, $b);

				}

			}

			$this->view = GM_PREFERENCE;

		} /* else { */

/* 			$this->created = 0; */

/* 			$this->snapshot_error = "libgmailer: no snapshot type specified";  // Added by Neerav; 3 Aug 2005 */

/* 			return null; */

/* 		} */



		$this->created = 1;

		return 1;

	}				 

}





/**

 * Class Debugger

 *

 * @package GMailer 

*/

class Debugger {	

   /**

    * Record debugging message.

    *

    * @param string $str Message to be recorded

    * @return void

    * @static

   */

	function say($str) {

		global $D_FILE, $D_ON;

		if ($D_ON) {

			$fd = fopen($D_FILE, "a+");

			$str = str_replace("*/", "*", $str);   // possible security hole

			fwrite($fd, "<?php /** ".$str." **/ ?".">\n");

			fclose($fd);

		}

	}

}	 

?>