Guest User

Exchange WebDAV

a guest
Feb 16th, 2012
32
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 11.32 KB | None | 0 0
  1.  
  2. <?
  3.     class exchangeMail {
  4.         # Mail: New             #
  5.         # Mail: Attach          #
  6.         # Mail: Send            #
  7.         # Calendar: New         #
  8.         # Calendar: Edit
  9.         # Calendar: Delete
  10.         # Calendar: Send        #
  11.         public $log;
  12.         public $method;
  13.         public $headers;
  14.         public $url;
  15.         public $status;
  16.         public $xmlrequest;
  17.         public $timeout=60;
  18.         public $domain='domain.com'; # This should be domain.com, no http:// or www.
  19.         public $server='http://www.domain.com/Exchange'; # Full path to Exchange folder on server
  20.         public $port=80; # Change to 443 for https
  21.         public $protocol='http://'; # Change to https:// for port 443
  22.         public $username;
  23.         public $encrypted;
  24.         public $unreadEmails=0;
  25.         public $header;
  26.         public $body;
  27.         public $index;
  28.         public $data;
  29.         public $stack;
  30.         public $XMLParser;
  31.  
  32.         public function __construct($mailbox) {
  33.        
  34.             $this->log.="New HTTP Request.<br />\n"; $this->reset(0); $this->headers=array('Content-Type'=>'text/xml; charset="UTF-8"','Depth'=>0,'Translate'=>'f');
  35.             $this->username='[enter username here]'; $this->mailbox=$mailbox; $this->encrypted=base64_decode('[enter username:password in base64 here]');
  36.            
  37.             // http://schemas.microsoft.com/exchange/outlookmessageclass
  38.             // http://www.outlook-tips.net/howto/commandlines.htm
  39.             // http://msdn.microsoft.com/en-us/library/aa486269%28v=EXCHG.65%29.aspx (Exchange Schema)
  40.            
  41.             $this->xmlrequest="
  42.                 <?xml version=\"1.0\"?>
  43.                 <dav:propertyupdate
  44.                     xmlns:dav=\"DAV:\"
  45.                     xmlns:-xml=\"xml:\"
  46.                     xmlns:exchange=\"http://schemas.microsoft.com/exchange/\"
  47.                     xmlns:security=\"http://schemas.microsoft.com/exchange/security/\"
  48.                     xmlns:events=\"http://schemas.microsoft.com/exchange/events/\"
  49.                     xmlns:mapi=\"http://schemas.microsoft.com/mapi/\"
  50.                     xmlns:proptag=\"http://schemas.microsoft.com/mapi/proptag/\"
  51.                     xmlns:mapiext=\"http://schemas.microsoft.com/mapi/id/{00062002-0000-0000-C000-000000000046}/\"
  52.                     xmlns:calendar=\"urn:schemas:calendar:\"
  53.                     xmlns:contacts=\"urn:schemas:contacts:\"
  54.                     xmlns:header=\"urn:schemas:mailheader:\"
  55.                     xmlns:httpmail=\"urn:schemas:httpmail:\"
  56.                     xmlns:office=\"urn:schemas-microsoft-com:office:office\"
  57.                     xmlns:repl=\"http://schemas.microsoft.com/repl/\"
  58.                     xmlns:exchdata=\"urn:schemas-microsoft-com:exch-data:\"
  59.                     xmlns:datatype=\"urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/\"
  60.                     xmlns:msdatatype=\"urn:schemas-microsoft-com:datatypes\"
  61.                     xmlns:forms=\"urn:schemas-microsoft-com:office:forms\"
  62.                     xmlns:-xmldata=\"urn:schemas-microsoft-com:xml-data\"
  63.                     xmlns:fulltext=\"urn:schemas-microsoft-com:fulltextqueryinfo\"
  64.                     >
  65.             ";
  66.            
  67.             return true;
  68.         }
  69.         function fetch() {
  70.             $this->reset(0);
  71.             if(!$this->url or $this->url=="") { return false; }
  72.             if(!$fileHandle=$this->getContents()) { return false; }
  73.             $this->header=fgets($fileHandle, 1024); $this->status=substr($this->header,9,3);
  74.             $statusMessages=array('200'=>'Request OK','201'=>'Request Created','202'=>'Request Accepted','301'=>'Page Moved Permanently','304'=>'Page Not Modified','400'=>'Error: Bad Request','401'=>'Error: Unauthorized Request - Username and/or Password incorrect or not supplied','403'=>'Error: Forbidden','404'=>'Error: Not Found','405'=>'Error: Method Not Allowed','408'=>'Request Timed Out','413'=>'Request Entity Too Large','414'=>'Request URI Too Large','500'=>'Server Error: Internal Server Error','501'=>'Server Error: Not Implemented','502'=>'Server Error: Bad Gateway','503'=>'Server Error: Service Unavailable','504'=>'Server Error: Gateway Timed Out','505'=>'Server Error: HTTP Version not supported');
  75.             $this->statusMessage=(array_key_exists($this->status, $statusMessages))?$statusMessages[$this->status]:"Unsupported status code";
  76.             while((trim($line=fgets($fileHandle, 1024))!="") and (!feof($fileHandle))) { $this->header.=$line; if($this->status=="401" and strpos($line,"WWW-Authenticate: Basic realm=\"")===0) { fclose($fileHandle); return false; } }
  77.             while(!feof($fileHandle)) { $this->body.=fgets($fileHandle, 1024); } fclose($fileHandle);
  78.             $this->get($this->body);
  79.             return $this->status;
  80.         }
  81.         function getContents() {
  82.             preg_match("~([a-z]*://)?([^/]*)(/.*)?~i", $this->url, $parts); $path=($parts[3]=="")?"/":$parts[3];
  83.             if(!$sock=@fsockopen($this->domain, $this->port, $errorNumber, $errorString, $this->timeout)) { $this->log.="Could not open connection. Error ".$errorNumber.": ".$errorString."<br />\n"; return false; }
  84.             stream_set_timeout($sock, $this->timeout);
  85.             $this->headers['Host']=$this->domain.":".$this->port;
  86.             $this->headers['Authorization']="Basic ".$this->encrypted;
  87.             if(strlen($this->xmlrequest)>0) { $this->log.="XML request will be sent<br />\n"; $request=$this->method." ".$path." HTTP/1.0\r\n"; $this->headers['Content-Length']=strlen($this->xmlrequest); } else { $this->log.="XML Request not set<br />\n"; exit; }
  88.             if(fwrite($sock, $request)===FALSE) { fclose($sock); return false; } foreach($this->headers as $key=>$value) { if(fwrite($sock, $key.": ".$value."\r\n")===FALSE) { fclose($sock); return false; } } if(fwrite($sock, "\r\n")===FALSE) { fclose($sock); return false; } if(strlen($this->xmlrequest)>0) { if(fwrite($sock, $this->xmlrequest."\r\n")===FALSE) { fclose($sock); return false; } } return $sock;
  89.         }
  90.         function get($inputXML) { $this->reset(1); xml_set_object($this->XMLParser,$this); xml_set_element_handler($this->XMLParser, "parseStart", "parseEnd"); xml_set_character_data_handler($this->XMLParser, "characterData"); xml_parser_set_option($this->XMLParser, XML_OPTION_TARGET_ENCODING, "UTF-8"); if(!$XMLParsed=xml_parse($this->XMLParser, $inputXML, true )) { return false; } xml_parser_free($this->XMLParser); return true; }
  91.         function parseStart($XMLParser, $XMLTag, $XMLAttributes) { $XMLTag=str_replace(":", "_", str_replace("-", "_", $XMLTag)); $object=new stdClass(); $object->_attr=new stdClass(); foreach($XMLAttributes as $key => $value) { $key=str_replace(":", "_", str_replace("-", "_", $key)); $object->_attr->$key=new stdClass(); $object->_attr->$key=$this->clean($value); } $temp=&$this->stack[$this->index]->$XMLTag; $temp[]=&$object; $size=sizeof($temp); $this->stack[]=&$temp[$size-1]; $this->index++; }
  92.         function parseEnd($XMLParser, $XMLTag) { array_pop($this->stack); $this->index--; }
  93.         function characterData($XMLParser, $data) { if(trim($data)) { $this->stack[$this->index]=new stdClass(); $this->stack[$this->index]->_text.=$data; } }
  94.         function clean($input) { return utf8_decode(trim($input)); }
  95.         function reset($type) { if($type==0 OR !$type) { $this->header=""; $this->body=""; $this->status=""; $this->headers['User-Agent']=(isset($_SERVER['HTTP_USER_AGENT']))?$_SERVER['HTTP_USER_AGENT']:"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)"; $this->headers['Referer']=(substr($_SERVER['SERVER_PROTOCOL'],0,5)=="HTTPS")?"https://".$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']:"http://".$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']; } else if($type==1) { $this->index=0; $this->data=null; $this->stack=array(); $this->stack[]=&$this->data; $this->XMLParser=xml_parser_create("UTF-8"); } }
  96.         /*
  97.             /c ipm.appointment creates an appointment
  98.             /c ipm.note creates an e-mail message
  99.             /c ipm.schedule.meeting.request creates a meeting request
  100.             /c ipm.schedule.meeting.canceled creates a meeting cancellation
  101.         */
  102.        
  103.         function create($array=array()) {
  104.             $folderName=array('message'=>'Drafts','request'=>'Calendar','cancellation'=>'Calendar');
  105.             if(!isset($array['object_type']) OR empty($array['object_type'])) { return false; } $objectType=$array['object_type']; unset($array['object_type']);
  106.             if(array_key_exists($objectType,$folderName)) {
  107.                 $message=array('dav:contentclass'=>'urn:content-classes:message','exchange:outlookmessageclass'=>'IPM.Note');
  108.                 $request=array('dav:contentclass'=>'urn:content-classes:calendarmessage','exchange:outlookmessageclass'=>'IPM.Schedule.Meeting.Request');
  109.                 $cancellation=array('dav:contentclass'=>'urn:content-classes:calendarmessage','exchange:outlookmessageclass'=>'IPM.Schedule.Meeting.Canceled');
  110.                 $array=array_merge($$objectType,array_merge($array,array('header:content-base'=>'http://localhost/exchange/'))); # You may need to change the URL here
  111.                 $objectName=$folderName[$objectType].'/'.urlencode($array['httpmail:subject'].'#'.date('YmdHis',time()).'#').'.EML';
  112.                 $this->xmlrequest.="<dav:set><dav:prop>"; foreach($array as $key => $value) { $this->xmlrequest.="<$key>$value</$key>"; } $this->xmlrequest.="</dav:prop></dav:set></dav:propertyupdate>";
  113.                 $this->method='PROPPATCH'; $this->url=$this->server.'/'.$this->mailbox.'/'.$objectName; $this->fetch();
  114.             }
  115.         }
  116.         function attach($path,$name) {
  117.             $this->method='PUT'; $messageURL=$this->url; $this->url=$this->url.'/'.urlencode($name); $this->xmlrequest='';
  118.             if(!$fileHandle=fopen($path, 'r')) { return 'Unable to open file for reading.'; }
  119.             while(!feof($fileHandle)) { $this->xmlrequest.=fread($fileHandle, 1024); } $this->fetch();
  120.             $this->url=$messageURL; $this->xmlrequest="<?xml version=\"1.0\"?><dav:propertyupdate xmlns:dav=\"DAV:\" xmlns:header=\"urn:schemas:mailheader:\" xmlns:httpmail=\"urn:schemas:httpmail:\"><dav:set><dav:prop><header:content-disposition>attachment; filename=$name</header:content-disposition><httpmail:attachmentfilename>$name</httpmail:attachmentfilename></dav:prop></dav:set></dav:propertyupdate>"; $this->fetch();
  121.         }
  122.         function send() { $this->method="MOVE"; $this->headers["Destination"]=$this->server.'/'.$this->mailbox.'/%23%23DAVMailSubmissionURI%23%23/'; $this->xmlrequest="</dav:propertyupdate>"; $this->fetch(); }
  123.         function unread() {
  124.             global $_SESSION; $this->method='SEARCH'; $this->url=$this->server.'/'.$this->mailbox.'/Inbox/';
  125.             $this->unreadEmails=0; $folderArray=array('Inbox'); if($_SESSION['exchange_search_junk']==1) { $folderArray[]='Junk%20E-mail'; } if($_SESSION['exchange_search_deleted']==1) { $folderArray[]='Deleted%20Items'; }
  126.             $this->xmlrequest="<?xml version=\"1.0\"?><dav:searchrequest xmlns:dav=\"DAV:\" xmlns:security=\"http://schemas.microsoft.com/exchange/security/\"><dav:sql>SELECT \"urn:schemas:httpmail:unreadcount\" FROM \"".$this->server."/".$this->mailbox."/\"</dav:sql></dav:searchrequest>"; $this->fetch();
  127.             foreach($this->data->A_MULTISTATUS[0]->A_RESPONSE as $response) { if(in_array(preg_replace("=/=","", preg_replace("#".$this->server."/".$this->mailbox."/#i","",$response->A_HREF[0]->_text)),$folderArray)) { if(!empty($response->A_PROPSTAT[0]->A_PROP[0]->D_UNREADCOUNT[0]->_text)) { $this->unreadEmails+=($response->A_PROPSTAT[0]->A_PROP[0]->D_UNREADCOUNT[0]->_text); } } }
  128.             if($_SESSION['exchange_search_recursive']==1) { for($i=0; $i<count($folderArray); $i++) { $folderName=$folderArray[$i]; $this->xmlrequest="<?xml version=\"1.0\"?><dav:searchrequest xmlns:dav=\"DAV:\" xmlns:security=\"http://schemas.microsoft.com/exchange/security/\"><dav:sql>SELECT \"urn:schemas:httpmail:unreadcount\"FROM SCOPE('hierarchical traversal of \"".$this->server."/".$this->mailbox."/".$folderName."/\"')</dav:sql></dav:searchrequest>"; $this->fetch(); if(!empty($this->data->A_MULTISTATUS[0]->A_RESPONSE)) { foreach($this->data->A_MULTISTATUS[0]->A_RESPONSE as $response) { $unreadCount=0; if(!empty($response->A_PROPSTAT[0]->A_PROP[0]->D_UNREADCOUNT[0]->_text)) { $unreadCount=$response->A_PROPSTAT[0]->A_PROP[0]->D_UNREADCOUNT[0]->_text; } $folderArray[]=preg_replace("#".$this->server."/".$this->mailbox."/#i","",$response->A_HREF[0]->_text); $this->unreadEmails+=($unreadCount); } } } }
  129.         }
  130.     }
  131. ?>
Add Comment
Please, Sign In to add comment