1 | <?php |
---|
2 | /*********************************************** |
---|
3 | * File : imap.php |
---|
4 | * Project : Z-Push |
---|
5 | * Descr : This backend is based on |
---|
6 | * 'BackendDiff' and implements an |
---|
7 | * IMAP interface |
---|
8 | * |
---|
9 | * Created : 10.10.2007 |
---|
10 | * |
---|
11 | * ᅵ Zarafa Deutschland GmbH, www.zarafaserver.de |
---|
12 | * This file is distributed under GPL v2. |
---|
13 | * Consult LICENSE file for details |
---|
14 | ************************************************/ |
---|
15 | |
---|
16 | include_once('diffbackend.php'); |
---|
17 | |
---|
18 | // The is an improved version of mimeDecode from PEAR that correctly |
---|
19 | // handles charsets and charset conversion |
---|
20 | include_once('mimeDecode.php'); |
---|
21 | require_once('z_RFC822.php'); |
---|
22 | |
---|
23 | class BackendIMAP extends BackendDiff { |
---|
24 | /* Called to logon a user. These are the three authentication strings that you must |
---|
25 | * specify in ActiveSync on the PDA. Normally you would do some kind of password |
---|
26 | * check here. Alternatively, you could ignore the password here and have Apache |
---|
27 | * do authentication via mod_auth_* |
---|
28 | */ |
---|
29 | function Logon($username, $domain, $password) { |
---|
30 | $this->_wasteID = false; |
---|
31 | $this->_sentID = false; |
---|
32 | $this->_server = "{" . IMAP_SERVER . ":" . IMAP_PORT . "/imap" . IMAP_OPTIONS . "}"; |
---|
33 | |
---|
34 | if (!function_exists("imap_open")) |
---|
35 | debugLog("ERROR BackendIMAP : PHP-IMAP module not installed!!!!!"); |
---|
36 | |
---|
37 | // open the IMAP-mailbox |
---|
38 | $this->_mbox = @imap_open($this->_server , $username, $password, OP_HALFOPEN); |
---|
39 | $this->_mboxFolder = ""; |
---|
40 | |
---|
41 | if ($this->_mbox) { |
---|
42 | debugLog("IMAP connection opened sucessfully "); |
---|
43 | $this->_username = $username; |
---|
44 | $this->_domain = $domain; |
---|
45 | // set serverdelimiter |
---|
46 | $this->_serverdelimiter = $this->getServerDelimiter(); |
---|
47 | return true; |
---|
48 | } |
---|
49 | else { |
---|
50 | debugLog("IMAP can't connect: " . imap_last_error()); |
---|
51 | return false; |
---|
52 | } |
---|
53 | } |
---|
54 | |
---|
55 | /* Called before shutting down the request to close the IMAP connection |
---|
56 | */ |
---|
57 | function Logoff() { |
---|
58 | if ($this->_mbox) { |
---|
59 | // list all errors |
---|
60 | $errors = imap_errors(); |
---|
61 | if (is_array($errors)) { |
---|
62 | foreach ($errors as $e) debugLog("IMAP-errors: $e"); |
---|
63 | } |
---|
64 | @imap_close($this->_mbox); |
---|
65 | debugLog("IMAP connection closed"); |
---|
66 | } |
---|
67 | } |
---|
68 | |
---|
69 | /* Called directly after the logon. This specifies the client's protocol version |
---|
70 | * and device id. The device ID can be used for various things, including saving |
---|
71 | * per-device state information. |
---|
72 | * The $user parameter here is normally equal to the $username parameter from the |
---|
73 | * Logon() call. In theory though, you could log on a 'foo', and then sync the emails |
---|
74 | * of user 'bar'. The $user here is the username specified in the request URL, while the |
---|
75 | * $username in the Logon() call is the username which was sent as a part of the HTTP |
---|
76 | * authentication. |
---|
77 | */ |
---|
78 | function Setup($user, $devid, $protocolversion) { |
---|
79 | $this->_user = $user; |
---|
80 | $this->_devid = $devid; |
---|
81 | $this->_protocolversion = $protocolversion; |
---|
82 | |
---|
83 | return true; |
---|
84 | } |
---|
85 | |
---|
86 | /* Sends a message which is passed as rfc822. You basically can do two things |
---|
87 | * 1) Send the message to an SMTP server as-is |
---|
88 | * 2) Parse the message yourself, and send it some other way |
---|
89 | * It is up to you whether you want to put the message in the sent items folder. If you |
---|
90 | * want it in 'sent items', then the next sync on the 'sent items' folder should return |
---|
91 | * the new message as any other new message in a folder. |
---|
92 | */ |
---|
93 | function SendMail($rfc822, $forward = false, $reply = false, $parent = false) { |
---|
94 | debugLog("IMAP-SendMail: " . $rfc822 . "for: $forward reply: $reply parent: $parent" ); |
---|
95 | |
---|
96 | $mobj = new Mail_mimeDecode($rfc822); |
---|
97 | $message = $mobj->decode(array('decode_headers' => false, 'decode_bodies' => true, 'include_bodies' => true, 'input' => $rfc822, 'crlf' => "\n", 'charset' => 'utf-8')); |
---|
98 | |
---|
99 | $toaddr = $ccaddr = $bccaddr = ""; |
---|
100 | if(isset($message->headers["to"])) |
---|
101 | $toaddr = $this->parseAddr(Mail_RFC822::parseAddressList($message->headers["to"])); |
---|
102 | if(isset($message->headers["cc"])) |
---|
103 | $ccaddr = $this->parseAddr(Mail_RFC822::parseAddressList($message->headers["cc"])); |
---|
104 | if(isset($message->headers["bcc"])) |
---|
105 | $bccaddr = $this->parseAddr(Mail_RFC822::parseAddressList($message->headers["bcc"])); |
---|
106 | |
---|
107 | // save some headers when forwarding mails (content type & transfer-encoding) |
---|
108 | $headers = ""; |
---|
109 | $forward_h_ct = ""; |
---|
110 | $forward_h_cte = ""; |
---|
111 | |
---|
112 | $use_orgbody = false; |
---|
113 | |
---|
114 | // clean up the transmitted headers |
---|
115 | // remove default headers because we are using imap_mail |
---|
116 | $changedfrom = false; |
---|
117 | $returnPathSet = false; |
---|
118 | $body_base64 = false; |
---|
119 | $org_charset = ""; |
---|
120 | foreach($message->headers as $k => $v) { |
---|
121 | if ($k == "subject" || $k == "to" || $k == "cc" || $k == "bcc") |
---|
122 | continue; |
---|
123 | |
---|
124 | if ($k == "content-type") { |
---|
125 | // save the original content-type header for the body part when forwarding |
---|
126 | if ($forward) { |
---|
127 | $forward_h_ct = $v; |
---|
128 | continue; |
---|
129 | } |
---|
130 | |
---|
131 | // set charset always to utf-8 |
---|
132 | $org_charset = $v; |
---|
133 | $v = preg_replace("/charset=([A-Za-z0-9-\"']+)/", "charset=\"utf-8\"", $v); |
---|
134 | } |
---|
135 | |
---|
136 | if ($k == "content-transfer-encoding") { |
---|
137 | // if the content was base64 encoded, encode the body again when sending |
---|
138 | if (trim($v) == "base64") $body_base64 = true; |
---|
139 | |
---|
140 | // save the original encoding header for the body part when forwarding |
---|
141 | if ($forward) { |
---|
142 | $forward_h_cte = $v; |
---|
143 | continue; |
---|
144 | } |
---|
145 | } |
---|
146 | |
---|
147 | // if the message is a multipart message, then we should use the sent body |
---|
148 | if (!$forward && $k == "content-type" && preg_match("/multipart/i", $v)) { |
---|
149 | $use_orgbody = true; |
---|
150 | } |
---|
151 | |
---|
152 | // check if "from"-header is set |
---|
153 | if ($k == "from" && ! trim($v) && IMAP_DEFAULTFROM) { |
---|
154 | $changedfrom = true; |
---|
155 | if (IMAP_DEFAULTFROM == 'username') $v = $this->_username; |
---|
156 | else if (IMAP_DEFAULTFROM == 'domain') $v = $this->_domain; |
---|
157 | else $v = $this->_username . IMAP_DEFAULTFROM; |
---|
158 | } |
---|
159 | |
---|
160 | // check if "Return-Path"-header is set |
---|
161 | if ($k == "return-path") { |
---|
162 | $returnPathSet = true; |
---|
163 | if (! trim($v) && IMAP_DEFAULTFROM) { |
---|
164 | if (IMAP_DEFAULTFROM == 'username') $v = $this->_username; |
---|
165 | else if (IMAP_DEFAULTFROM == 'domain') $v = $this->_domain; |
---|
166 | else $v = $this->_username . IMAP_DEFAULTFROM; |
---|
167 | } |
---|
168 | } |
---|
169 | |
---|
170 | // all other headers stay |
---|
171 | if ($headers) $headers .= "\n"; |
---|
172 | $headers .= ucfirst($k) . ": ". $v; |
---|
173 | } |
---|
174 | |
---|
175 | // set "From" header if not set on the device |
---|
176 | if(IMAP_DEFAULTFROM && !$changedfrom){ |
---|
177 | if (IMAP_DEFAULTFROM == 'username') $v = $this->_username; |
---|
178 | else if (IMAP_DEFAULTFROM == 'domain') $v = $this->_domain; |
---|
179 | else $v = $this->_username . IMAP_DEFAULTFROM; |
---|
180 | if ($headers) $headers .= "\n"; |
---|
181 | $headers .= 'From: '.$v; |
---|
182 | } |
---|
183 | |
---|
184 | // set "Return-Path" header if not set on the device |
---|
185 | if(IMAP_DEFAULTFROM && !$returnPathSet){ |
---|
186 | if (IMAP_DEFAULTFROM == 'username') $v = $this->_username; |
---|
187 | else if (IMAP_DEFAULTFROM == 'domain') $v = $this->_domain; |
---|
188 | else $v = $this->_username . IMAP_DEFAULTFROM; |
---|
189 | if ($headers) $headers .= "\n"; |
---|
190 | $headers .= 'Return-Path: '.$v; |
---|
191 | } |
---|
192 | |
---|
193 | // if this is a multipart message with a boundary, we must use the original body |
---|
194 | if ($use_orgbody) { |
---|
195 | list(,$body) = $mobj->_splitBodyHeader($rfc822); |
---|
196 | } |
---|
197 | else |
---|
198 | $body = $this->getBody($message); |
---|
199 | |
---|
200 | // reply |
---|
201 | if (isset($reply) && isset($parent) && $reply && $parent) { |
---|
202 | $this->imap_reopenFolder($parent); |
---|
203 | // receive entire mail (header + body) to decode body correctly |
---|
204 | $origmail = @imap_fetchheader($this->_mbox, $reply, FT_PREFETCHTEXT | FT_UID) . @imap_body($this->_mbox, $reply, FT_PEEK | FT_UID); |
---|
205 | $mobj2 = new Mail_mimeDecode($origmail); |
---|
206 | // receive only body |
---|
207 | $body .= $this->getBody($mobj2->decode(array('decode_headers' => false, 'decode_bodies' => true, 'include_bodies' => true, 'input' => $origmail, 'crlf' => "\n", 'charset' => 'utf-8'))); |
---|
208 | // unset mimedecoder & origmail - free memory |
---|
209 | unset($mobj2); |
---|
210 | unset($origmail); |
---|
211 | } |
---|
212 | |
---|
213 | // encode the body to base64 if it was sent originally in base64 by the pda |
---|
214 | // the encoded body is included in the forward |
---|
215 | if ($body_base64) $body = base64_encode($body); |
---|
216 | |
---|
217 | |
---|
218 | // forward |
---|
219 | if (isset($forward) && isset($parent) && $forward && $parent) { |
---|
220 | $this->imap_reopenFolder($parent); |
---|
221 | // receive entire mail (header + body) |
---|
222 | $origmail = @imap_fetchheader($this->_mbox, $forward, FT_PREFETCHTEXT | FT_UID) . @imap_body($this->_mbox, $forward, FT_PEEK | FT_UID); |
---|
223 | |
---|
224 | // build a new mime message, forward entire old mail as file |
---|
225 | list($aheader, $body) = $this->mail_attach("forwarded_message.eml",strlen($origmail),$origmail, $body, $forward_h_ct, $forward_h_cte); |
---|
226 | |
---|
227 | // unset origmail - free memory |
---|
228 | unset($origmail); |
---|
229 | |
---|
230 | // add boundary headers |
---|
231 | $headers .= "\n" . $aheader; |
---|
232 | } |
---|
233 | |
---|
234 | //advanced debugging |
---|
235 | //debugLog("IMAP-SendMail: parsed message: ". print_r($message,1)); |
---|
236 | //debugLog("IMAP-SendMail: headers: $headers"); |
---|
237 | //debugLog("IMAP-SendMail: subject: {$message->headers["subject"]}"); |
---|
238 | //debugLog("IMAP-SendMail: body: $body"); |
---|
239 | |
---|
240 | $send = @imap_mail ( $toaddr, $message->headers["subject"], $body, $headers, $ccaddr, $bccaddr); |
---|
241 | |
---|
242 | // email sent? |
---|
243 | if (!$send) { |
---|
244 | debugLog("The email could not be sent. Last-IMAP-error: ". imap_last_error()); |
---|
245 | } |
---|
246 | |
---|
247 | // add message to the sent folder |
---|
248 | // build complete headers |
---|
249 | $cheaders = "To: " . $toaddr. "\n"; |
---|
250 | $cheaders .= "Subject: " . $message->headers["subject"] . "\n"; |
---|
251 | $cheaders .= "Cc: " . $ccaddr . "\n"; |
---|
252 | $cheaders .= $headers; |
---|
253 | |
---|
254 | $asf = false; |
---|
255 | if ($this->_sentID) { |
---|
256 | $asf = $this->addSentMessage($this->_sentID, $cheaders, $body); |
---|
257 | } |
---|
258 | else if (IMAP_SENTFOLDER) { |
---|
259 | $asf = $this->addSentMessage(IMAP_SENTFOLDER, $cheaders, $body); |
---|
260 | debugLog("IMAP-SendMail: Outgoing mail saved in configured 'Sent' folder '".IMAP_SENTFOLDER."': ". (($asf)?"success":"failed")); |
---|
261 | } |
---|
262 | // No Sent folder set, try defaults |
---|
263 | else { |
---|
264 | debugLog("IMAP-SendMail: No Sent mailbox set"); |
---|
265 | if($this->addSentMessage("INBOX.Sent", $cheaders, $body)) { |
---|
266 | debugLog("IMAP-SendMail: Outgoing mail saved in 'INBOX.Sent'"); |
---|
267 | $asf = true; |
---|
268 | } |
---|
269 | else if ($this->addSentMessage("Sent", $cheaders, $body)) { |
---|
270 | debugLog("IMAP-SendMail: Outgoing mail saved in 'Sent'"); |
---|
271 | $asf = true; |
---|
272 | } |
---|
273 | else if ($this->addSentMessage("Sent Items", $cheaders, $body)) { |
---|
274 | debugLog("IMAP-SendMail: Outgoing mail saved in 'Sent Items'"); |
---|
275 | $asf = true; |
---|
276 | } |
---|
277 | } |
---|
278 | |
---|
279 | // unset mimedecoder - free memory |
---|
280 | unset($mobj); |
---|
281 | return ($send && $asf); |
---|
282 | } |
---|
283 | |
---|
284 | /* Should return a wastebasket folder if there is one. This is used when deleting |
---|
285 | * items; if this function returns a valid folder ID, then all deletes are handled |
---|
286 | * as moves and are sent to your backend as a move. If it returns FALSE, then deletes |
---|
287 | * are always handled as real deletes and will be sent to your importer as a DELETE |
---|
288 | */ |
---|
289 | function GetWasteBasket() { |
---|
290 | return $this->_wasteID; |
---|
291 | } |
---|
292 | |
---|
293 | /* Should return a list (array) of messages, each entry being an associative array |
---|
294 | * with the same entries as StatMessage(). This function should return stable information; ie |
---|
295 | * if nothing has changed, the items in the array must be exactly the same. The order of |
---|
296 | * the items within the array is not important though. |
---|
297 | * |
---|
298 | * The cutoffdate is a date in the past, representing the date since which items should be shown. |
---|
299 | * This cutoffdate is determined by the user's setting of getting 'Last 3 days' of e-mail, etc. If |
---|
300 | * you ignore the cutoffdate, the user will not be able to select their own cutoffdate, but all |
---|
301 | * will work OK apart from that. |
---|
302 | */ |
---|
303 | |
---|
304 | function GetMessageList($folderid, $cutoffdate) { |
---|
305 | debugLog("IMAP-GetMessageList: (fid: '$folderid' cutdate: '$cutoffdate' )"); |
---|
306 | |
---|
307 | $messages = array(); |
---|
308 | $this->imap_reopenFolder($folderid, true); |
---|
309 | |
---|
310 | $sequence = "1:*"; |
---|
311 | if ($cutoffdate > 0) { |
---|
312 | $search = @imap_search($this->_mbox, "SINCE ". date("d-M-Y", $cutoffdate)); |
---|
313 | if ($search !== false) |
---|
314 | $sequence = implode(",", $search); |
---|
315 | if (TRACE_UID !== false and (TRACE_TYPE == 'IMAP' or TRACE_TYPE == 'ALL')) traceLog('IMAP::GetMessageList-> A função @imap_search leu as seguintes SEQUÊNCIAS do servidor IMAP com base no filtro de data: '.$sequence); |
---|
316 | } |
---|
317 | |
---|
318 | $overviews = @imap_fetch_overview($this->_mbox, $sequence); |
---|
319 | |
---|
320 | if (!$overviews) { |
---|
321 | debugLog("IMAP-GetMessageList: Failed to retrieve overview"); |
---|
322 | } else { |
---|
323 | foreach($overviews as $overview) { |
---|
324 | $date = ""; |
---|
325 | $vars = get_object_vars($overview); |
---|
326 | if (TRACE_UID !== false and (TRACE_TYPE == 'IMAP' or TRACE_TYPE == 'ALL')) traceLog('IMAP::GetMessageList-> A função @imap_fetch_overview leu mais detalhes da mensagem: '. print_r($overview,1)); |
---|
327 | if (array_key_exists( "date", $vars)) { |
---|
328 | // message is out of range for cutoffdate, ignore it |
---|
329 | if(strtotime(preg_replace("/\(.*\)/", "", $overview->date)) < $cutoffdate) { // emerson-faria.nobre@serpro.gov.br - 07/feb/2011 |
---|
330 | if (TRACE_UID !== false and (TRACE_TYPE == 'IMAP' or TRACE_TYPE == 'ALL')) traceLog('IMAP::GetMessageList-> O overview->date: '.$overview->date.' (overview->date_timestamp: '.strtotime(preg_replace("/\(.*\)/", "", $overview->date)).') é menor que o $cutoffdate: '.date("d/m/Y G:i:s",$cutoffdate).' ($cutoffdate_timestamp: '.$cutoffdate.') ou a função "strtotime" gerou um ERRO porque não conseguiu retornar um valor para o overview->date_timestamp. A mensagem será descartada da sincronização.'); |
---|
331 | continue; |
---|
332 | } |
---|
333 | //if(strtotime($overview->date) < $cutoffdate) continue; |
---|
334 | $date = $overview->date; |
---|
335 | } else if (TRACE_UID !== false and (TRACE_TYPE == 'IMAP' or TRACE_TYPE == 'ALL')) traceLog('IMAP::GetMessageList-> ERRO: O campo date não existe no overview da mensagem.'); |
---|
336 | |
---|
337 | // cut of deleted messages |
---|
338 | if (array_key_exists( "deleted", $vars) && $overview->deleted) { |
---|
339 | if (TRACE_UID !== false and (TRACE_TYPE == 'IMAP' or TRACE_TYPE == 'ALL')) traceLog('IMAP::GetMessageList-> A mensagem está com o flag deleted ativo e será descartada da sincronização'); |
---|
340 | continue; |
---|
341 | } |
---|
342 | |
---|
343 | if (array_key_exists( "uid", $vars)) { |
---|
344 | $message = array(); |
---|
345 | $message["mod"] = $date; |
---|
346 | $message["id"] = $overview->uid; |
---|
347 | // 'seen' aka 'read' is the only flag we want to know about |
---|
348 | $message["flags"] = 0; |
---|
349 | |
---|
350 | if(array_key_exists( "seen", $vars) && $overview->seen) |
---|
351 | $message["flags"] = 1; |
---|
352 | array_push($messages, $message); |
---|
353 | } else if (TRACE_UID !== false and (TRACE_TYPE == 'IMAP' or TRACE_TYPE == 'ALL')) traceLog('IMAP::GetMessageList-> ERRO: O campo uid não existe no overview da mensagem.'); |
---|
354 | } |
---|
355 | } |
---|
356 | return $messages; |
---|
357 | } |
---|
358 | |
---|
359 | /* This function is analogous to GetMessageList. |
---|
360 | * |
---|
361 | */ |
---|
362 | function GetFolderList() { |
---|
363 | $folders = array(); |
---|
364 | |
---|
365 | $list = @imap_getmailboxes($this->_mbox, $this->_server, "*"); |
---|
366 | if (is_array($list)) { |
---|
367 | // reverse list to obtain folders in right order |
---|
368 | $list = array_reverse($list); |
---|
369 | foreach ($list as $val) { |
---|
370 | if (TRACE_UID !== false and (TRACE_TYPE == 'IMAP' or TRACE_TYPE == 'ALL')) traceLog('IMAP::GetFolderList-> Pasta lida usando a função @imap_getmailboxes: '.print_r($val,1)); |
---|
371 | $box = array(); |
---|
372 | |
---|
373 | // cut off serverstring |
---|
374 | $box["id"] = imap_utf7_decode(substr($val->name, strlen($this->_server))); |
---|
375 | |
---|
376 | // always use "." as folder delimiter |
---|
377 | $box["id"] = imap_utf7_encode(str_replace($val->delimiter, ".", $box["id"])); |
---|
378 | |
---|
379 | // explode hierarchies |
---|
380 | $fhir = explode(".", $box["id"]); |
---|
381 | if (count($fhir) > 1) { |
---|
382 | $box["mod"] = imap_utf7_encode(array_pop($fhir)); // mod is last part of path |
---|
383 | $box["parent"] = imap_utf7_encode(implode(".", $fhir)); // parent is all previous parts of path |
---|
384 | } |
---|
385 | else { |
---|
386 | $box["mod"] = imap_utf7_encode($box["id"]); |
---|
387 | $box["parent"] = "0"; |
---|
388 | } |
---|
389 | if (TRACE_UID !== false and (TRACE_TYPE == 'IMAP' or TRACE_TYPE == 'ALL')) traceLog('IMAP::GetFolderList-> Parâmetros da pasta após decodificação: '.print_r($box,1)); |
---|
390 | $folders[]=$box; |
---|
391 | } |
---|
392 | } |
---|
393 | else { |
---|
394 | debugLog("GetFolderList: imap_list failed: " . imap_last_error()); |
---|
395 | } |
---|
396 | |
---|
397 | return $folders; |
---|
398 | } |
---|
399 | |
---|
400 | /* GetFolder should return an actual SyncFolder object with all the properties set. Folders |
---|
401 | * are pretty simple really, having only a type, a name, a parent and a server ID. |
---|
402 | */ |
---|
403 | |
---|
404 | function GetFolder($id) { |
---|
405 | $folder = new SyncFolder(); |
---|
406 | $folder->serverid = $id; |
---|
407 | |
---|
408 | // explode hierarchy |
---|
409 | $fhir = explode(".", $id); |
---|
410 | |
---|
411 | // compare on lowercase strings |
---|
412 | $lid = strtolower($id); |
---|
413 | |
---|
414 | if($lid == "inbox") { |
---|
415 | $folder->parentid = "0"; // Root |
---|
416 | $folder->displayname = "Inbox"; |
---|
417 | $folder->type = SYNC_FOLDER_TYPE_INBOX; |
---|
418 | } |
---|
419 | // Zarafa IMAP-Gateway outputs |
---|
420 | else if($lid == "drafts") { |
---|
421 | $folder->parentid = "0"; |
---|
422 | $folder->displayname = "Drafts"; |
---|
423 | $folder->type = SYNC_FOLDER_TYPE_DRAFTS; |
---|
424 | } |
---|
425 | else if($lid == "trash") { |
---|
426 | $folder->parentid = "0"; |
---|
427 | $folder->displayname = "Trash"; |
---|
428 | $folder->type = SYNC_FOLDER_TYPE_WASTEBASKET; |
---|
429 | $this->_wasteID = $id; |
---|
430 | } |
---|
431 | else if($lid == "sent" || $lid == "sent items" || $lid == IMAP_SENTFOLDER) { |
---|
432 | $folder->parentid = "0"; |
---|
433 | $folder->displayname = "Sent"; |
---|
434 | $folder->type = SYNC_FOLDER_TYPE_SENTMAIL; |
---|
435 | $this->_sentID = $id; |
---|
436 | } |
---|
437 | // courier-imap outputs |
---|
438 | else if($lid == "inbox.drafts") { |
---|
439 | $folder->parentid = $fhir[0]; |
---|
440 | $folder->displayname = "Drafts"; |
---|
441 | $folder->type = SYNC_FOLDER_TYPE_DRAFTS; |
---|
442 | } |
---|
443 | else if($lid == "inbox.trash") { |
---|
444 | $folder->parentid = $fhir[0]; |
---|
445 | $folder->displayname = "Trash"; |
---|
446 | $folder->type = SYNC_FOLDER_TYPE_WASTEBASKET; |
---|
447 | $this->_wasteID = $id; |
---|
448 | } |
---|
449 | else if($lid == "inbox.sent") { |
---|
450 | $folder->parentid = $fhir[0]; |
---|
451 | $folder->displayname = "Sent"; |
---|
452 | $folder->type = SYNC_FOLDER_TYPE_SENTMAIL; |
---|
453 | $this->_sentID = $id; |
---|
454 | } |
---|
455 | |
---|
456 | // define the rest as other-folders |
---|
457 | else { |
---|
458 | if (count($fhir) > 1) { |
---|
459 | $folder->displayname = windows1252_to_utf8(imap_utf7_decode(array_pop($fhir))); |
---|
460 | $folder->parentid = implode(".", $fhir); |
---|
461 | } |
---|
462 | else { |
---|
463 | $folder->displayname = windows1252_to_utf8(imap_utf7_decode($id)); |
---|
464 | $folder->parentid = "0"; |
---|
465 | } |
---|
466 | $folder->type = SYNC_FOLDER_TYPE_OTHER; |
---|
467 | } |
---|
468 | |
---|
469 | //advanced debugging |
---|
470 | //debugLog("IMAP-GetFolder(id: '$id') -> " . print_r($folder, 1)); |
---|
471 | if (TRACE_UID !== false and (TRACE_TYPE == 'IMAP' or TRACE_TYPE == 'ALL')) traceLog('IMAP::GetFolder(id: '.$id.'): '.print_r($folder,1)); |
---|
472 | |
---|
473 | return $folder; |
---|
474 | } |
---|
475 | |
---|
476 | /* Return folder stats. This means you must return an associative array with the |
---|
477 | * following properties: |
---|
478 | * "id" => The server ID that will be used to identify the folder. It must be unique, and not too long |
---|
479 | * How long exactly is not known, but try keeping it under 20 chars or so. It must be a string. |
---|
480 | * "parent" => The server ID of the parent of the folder. Same restrictions as 'id' apply. |
---|
481 | * "mod" => This is the modification signature. It is any arbitrary string which is constant as long as |
---|
482 | * the folder has not changed. In practice this means that 'mod' can be equal to the folder name |
---|
483 | * as this is the only thing that ever changes in folders. (the type is normally constant) |
---|
484 | */ |
---|
485 | function StatFolder($id) { |
---|
486 | $folder = $this->GetFolder($id); |
---|
487 | |
---|
488 | $stat = array(); |
---|
489 | $stat["id"] = $id; |
---|
490 | $stat["parent"] = $folder->parentid; |
---|
491 | $stat["mod"] = $folder->displayname; |
---|
492 | if (TRACE_UID !== false and (TRACE_TYPE == 'IMAP' or TRACE_TYPE == 'ALL')) traceLog('IMAP::StatFolder(id: '.$id.'): '.print_r($stat,1)); |
---|
493 | return $stat; |
---|
494 | } |
---|
495 | |
---|
496 | /* Creates or modifies a folder |
---|
497 | * "folderid" => id of the parent folder |
---|
498 | * "oldid" => if empty -> new folder created, else folder is to be renamed |
---|
499 | * "displayname" => new folder name (to be created, or to be renamed to) |
---|
500 | * "type" => folder type, ignored in IMAP |
---|
501 | * |
---|
502 | */ |
---|
503 | function ChangeFolder($folderid, $oldid, $displayname, $type){ |
---|
504 | debugLog("ChangeFolder: (parent: '$folderid' oldid: '$oldid' displayname: '$displayname' type: '$type')"); |
---|
505 | |
---|
506 | // go to parent mailbox |
---|
507 | $this->imap_reopenFolder($folderid); |
---|
508 | |
---|
509 | // build name for new mailbox |
---|
510 | $newname = $this->_server . str_replace(".", $this->_serverdelimiter, $folderid) . $this->_serverdelimiter . $displayname; |
---|
511 | |
---|
512 | $csts = false; |
---|
513 | // if $id is set => rename mailbox, otherwise create |
---|
514 | if ($oldid) { |
---|
515 | // rename doesn't work properly with IMAP |
---|
516 | // the activesync client doesn't support a 'changing ID' |
---|
517 | //$csts = imap_renamemailbox($this->_mbox, $this->_server . imap_utf7_encode(str_replace(".", $this->_serverdelimiter, $oldid)), $newname); |
---|
518 | } |
---|
519 | else { |
---|
520 | $csts = @imap_createmailbox($this->_mbox, $newname); |
---|
521 | } |
---|
522 | if ($csts) { |
---|
523 | return $this->StatFolder($folderid . "." . $displayname); |
---|
524 | } |
---|
525 | else |
---|
526 | return false; |
---|
527 | } |
---|
528 | |
---|
529 | /* Should return attachment data for the specified attachment. The passed attachment identifier is |
---|
530 | * the exact string that is returned in the 'AttName' property of an SyncAttachment. So, you should |
---|
531 | * encode any information you need to find the attachment in that 'attname' property. |
---|
532 | */ |
---|
533 | function GetAttachmentData($attname) { |
---|
534 | debugLog("getAttachmentDate: (attname: '$attname')"); |
---|
535 | |
---|
536 | list($folderid, $id, $part) = explode(":", $attname); |
---|
537 | |
---|
538 | $this->imap_reopenFolder($folderid); |
---|
539 | $mail = @imap_fetchheader($this->_mbox, $id, FT_PREFETCHTEXT | FT_UID) . @imap_body($this->_mbox, $id, FT_PEEK | FT_UID); |
---|
540 | |
---|
541 | $mobj = new Mail_mimeDecode($mail); |
---|
542 | $message = $mobj->decode(array('decode_headers' => true, 'decode_bodies' => true, 'include_bodies' => true, 'input' => $mail, 'crlf' => "\n", 'charset' => 'utf-8')); |
---|
543 | |
---|
544 | if (isset($message->parts[$part]->body)) |
---|
545 | print $message->parts[$part]->body; |
---|
546 | |
---|
547 | // unset mimedecoder & mail |
---|
548 | unset($mobj); |
---|
549 | unset($mail); |
---|
550 | return true; |
---|
551 | } |
---|
552 | |
---|
553 | /* StatMessage should return message stats, analogous to the folder stats (StatFolder). Entries are: |
---|
554 | * 'id' => Server unique identifier for the message. Again, try to keep this short (under 20 chars) |
---|
555 | * 'flags' => simply '0' for unread, '1' for read |
---|
556 | * 'mod' => modification signature. As soon as this signature changes, the item is assumed to be completely |
---|
557 | * changed, and will be sent to the PDA as a whole. Normally you can use something like the modification |
---|
558 | * time for this field, which will change as soon as the contents have changed. |
---|
559 | */ |
---|
560 | |
---|
561 | function StatMessage($folderid, $id) { |
---|
562 | debugLog("IMAP-StatMessage: (fid: '$folderid' id: '$id' )"); |
---|
563 | |
---|
564 | $this->imap_reopenFolder($folderid); |
---|
565 | $overview = @imap_fetch_overview( $this->_mbox , $id , FT_UID); |
---|
566 | |
---|
567 | if (!$overview) { |
---|
568 | debugLog("IMAP-StatMessage: Failed to retrieve overview: ". imap_last_error()); |
---|
569 | return false; |
---|
570 | } |
---|
571 | |
---|
572 | else { |
---|
573 | // check if variables for this overview object are available |
---|
574 | $vars = get_object_vars($overview[0]); |
---|
575 | |
---|
576 | if (TRACE_UID !== false and (TRACE_TYPE == 'IMAP' or TRACE_TYPE == 'ALL') and (! array_key_exists( "uid", $vars))) debugLog('IMAP::StatMessage-> ERRO: A mensagem será desconsiderada porque não tem o campo "uid"'); |
---|
577 | // without uid it's not a valid message |
---|
578 | if (! array_key_exists( "uid", $vars)) return false; |
---|
579 | |
---|
580 | |
---|
581 | $entry = array(); |
---|
582 | $entry["mod"] = (array_key_exists( "date", $vars)) ? $overview[0]->date : ""; |
---|
583 | $entry["id"] = $overview[0]->uid; |
---|
584 | // 'seen' aka 'read' is the only flag we want to know about |
---|
585 | $entry["flags"] = 0; |
---|
586 | |
---|
587 | if(array_key_exists( "seen", $vars) && $overview[0]->seen) |
---|
588 | $entry["flags"] = 1; |
---|
589 | |
---|
590 | if (TRACE_UID !== false and (TRACE_TYPE == 'IMAP' or TRACE_TYPE == 'ALL')) traceLog('IMAP::StatMessage: '.print_r($entry,1)); |
---|
591 | |
---|
592 | //advanced debugging |
---|
593 | //debugLog("IMAP-StatMessage-parsed: ". print_r($entry,1)); |
---|
594 | |
---|
595 | return $entry; |
---|
596 | } |
---|
597 | } |
---|
598 | |
---|
599 | /* GetMessage should return the actual SyncXXX object type. You may or may not use the '$folderid' parent folder |
---|
600 | * identifier here. |
---|
601 | * Note that mixing item types is illegal and will be blocked by the engine; ie returning an Email object in a |
---|
602 | * Tasks folder will not do anything. The SyncXXX objects should be filled with as much information as possible, |
---|
603 | * but at least the subject, body, to, from, etc. |
---|
604 | */ |
---|
605 | function GetMessage($folderid, $id, $truncsize, $mimesupport = 0) { |
---|
606 | debugLog("IMAP-GetMessage: (fid: '$folderid' id: '$id' truncsize: $truncsize)"); |
---|
607 | |
---|
608 | // Get flags, etc |
---|
609 | $stat = $this->StatMessage($folderid, $id); |
---|
610 | |
---|
611 | if ($stat) { |
---|
612 | $this->imap_reopenFolder($folderid); |
---|
613 | $mail = @imap_fetchheader($this->_mbox, $id, FT_PREFETCHTEXT | FT_UID) . @imap_body($this->_mbox, $id, FT_PEEK | FT_UID); |
---|
614 | |
---|
615 | if (TRACE_UID !== false and (TRACE_TYPE == 'IMAP' or TRACE_TYPE == 'ALL')) traceLog("IMAP-GetMessage: Mensagem lida do servidor IMAP através da função @imap_fetchheader: ". print_r($mail,1)); |
---|
616 | |
---|
617 | $mobj = new Mail_mimeDecode($mail); |
---|
618 | $message = $mobj->decode(array('decode_headers' => true, 'decode_bodies' => true, 'include_bodies' => true, 'input' => $mail, 'crlf' => "\n", 'charset' => 'utf-8')); |
---|
619 | |
---|
620 | if (TRACE_UID !== false and (TRACE_TYPE == 'IMAP' or TRACE_TYPE == 'ALL')) traceLog("IMAP-GetMessage: Mensagem mime decodificada: ". print_r($message,1)); |
---|
621 | |
---|
622 | $output = new SyncMail(); |
---|
623 | |
---|
624 | $body = $this->getBody($message); |
---|
625 | // truncate body, if requested |
---|
626 | if(strlen($body) > $truncsize) { |
---|
627 | $body = utf8_truncate($body, $truncsize); |
---|
628 | $output->bodytruncated = 1; |
---|
629 | } else { |
---|
630 | $body = $body; |
---|
631 | $output->bodytruncated = 0; |
---|
632 | } |
---|
633 | $body = str_replace("\n","\r\n", str_replace("\r","",$body)); |
---|
634 | |
---|
635 | $output->bodysize = strlen($body); |
---|
636 | $output->body = $body; |
---|
637 | //$output->datereceived = isset($message->headers["date"]) ? strtotime($message->headers["date"]) : null; |
---|
638 | $output->datereceived = isset($message->headers["date"]) ? strtotime(preg_replace("/\(.*\)/", "", $message->headers["date"])) : null; // emerson-faria.nobre@serpro.gov.br |
---|
639 | $output->displayto = isset($message->headers["to"]) ? $message->headers["to"] : null; |
---|
640 | $output->importance = isset($message->headers["x-priority"]) ? preg_replace("/\D+/", "", $message->headers["x-priority"]) : null; |
---|
641 | $output->messageclass = "IPM.Note"; |
---|
642 | $output->subject = isset($message->headers["subject"]) ? $message->headers["subject"] : ""; |
---|
643 | $output->read = $stat["flags"]; |
---|
644 | $output->to = isset($message->headers["to"]) ? $message->headers["to"] : null; |
---|
645 | $output->cc = isset($message->headers["cc"]) ? $message->headers["cc"] : null; |
---|
646 | $output->from = isset($message->headers["from"]) ? $message->headers["from"] : null; |
---|
647 | $output->reply_to = isset($message->headers["reply-to"]) ? $message->headers["reply-to"] : null; |
---|
648 | |
---|
649 | // Attachments are only searched in the top-level part |
---|
650 | $n = 0; |
---|
651 | if(isset($message->parts)) { |
---|
652 | foreach($message->parts as $part) { |
---|
653 | if(isset($part->disposition) && ($part->disposition == "attachment" || $part->disposition == "inline")) { |
---|
654 | $attachment = new SyncAttachment(); |
---|
655 | |
---|
656 | if (isset($part->body)) |
---|
657 | $attachment->attsize = strlen($part->body); |
---|
658 | |
---|
659 | if(isset($part->d_parameters['filename'])) |
---|
660 | $attname = $part->d_parameters['filename']; |
---|
661 | else if(isset($part->ctype_parameters['name'])) |
---|
662 | $attname = $part->ctype_parameters['name']; |
---|
663 | else if(isset($part->headers['content-description'])) |
---|
664 | $attname = $part->headers['content-description']; |
---|
665 | else $attname = "unknown attachment"; |
---|
666 | |
---|
667 | $attachment->displayname = $attname; |
---|
668 | $attachment->attname = $folderid . ":" . $id . ":" . $n; |
---|
669 | $attachment->attmethod = 1; |
---|
670 | $attachment->attoid = isset($part->headers['content-id']) ? $part->headers['content-id'] : ""; |
---|
671 | array_push($output->attachments, $attachment); |
---|
672 | } |
---|
673 | $n++; |
---|
674 | } |
---|
675 | } |
---|
676 | // unset mimedecoder & mail |
---|
677 | unset($mobj); |
---|
678 | unset($mail); |
---|
679 | if (TRACE_UID !== false and (TRACE_TYPE == 'IMAP' or TRACE_TYPE == 'ALL')) traceLog("IMAP-GetMessage: Mensagem formatada para envio ao celular: ". print_r($output,1)); |
---|
680 | return $output; |
---|
681 | } |
---|
682 | return false; |
---|
683 | } |
---|
684 | |
---|
685 | /* This function is called when the user has requested to delete (really delete) a message. Usually |
---|
686 | * this means just unlinking the file its in or somesuch. After this call has succeeded, a call to |
---|
687 | * GetMessageList() should no longer list the message. If it does, the message will be re-sent to the PDA |
---|
688 | * as it will be seen as a 'new' item. This means that if you don't implement this function, you will |
---|
689 | * be able to delete messages on the PDA, but as soon as you sync, you'll get the item back |
---|
690 | */ |
---|
691 | function DeleteMessage($folderid, $id) { |
---|
692 | debugLog("IMAP-DeleteMessage: (fid: '$folderid' id: '$id' )"); |
---|
693 | |
---|
694 | $this->imap_reopenFolder($folderid); |
---|
695 | $s1 = @imap_delete ($this->_mbox, $id, FT_UID); |
---|
696 | $s11 = @imap_setflag_full($this->_mbox, $id, "\\Deleted", FT_UID); |
---|
697 | $s2 = @imap_expunge($this->_mbox); |
---|
698 | |
---|
699 | debugLog("IMAP-DeleteMessage: s-delete: $s1 s-expunge: $s2 setflag: $s11"); |
---|
700 | |
---|
701 | return ($s1 && $s2 && $s11); |
---|
702 | } |
---|
703 | |
---|
704 | /* This should change the 'read' flag of a message on disk. The $flags |
---|
705 | * parameter can only be '1' (read) or '0' (unread). After a call to |
---|
706 | * SetReadFlag(), GetMessageList() should return the message with the |
---|
707 | * new 'flags' but should not modify the 'mod' parameter. If you do |
---|
708 | * change 'mod', simply setting the message to 'read' on the PDA will trigger |
---|
709 | * a full resync of the item from the server |
---|
710 | */ |
---|
711 | function SetReadFlag($folderid, $id, $flags) { |
---|
712 | debugLog("IMAP-SetReadFlag: (fid: '$folderid' id: '$id' flags: '$flags' )"); |
---|
713 | |
---|
714 | $this->imap_reopenFolder($folderid); |
---|
715 | |
---|
716 | if ($flags == 0) { |
---|
717 | // set as "Unseen" (unread) |
---|
718 | $status = @imap_clearflag_full ( $this->_mbox, $id, "\\Seen", ST_UID); |
---|
719 | } else { |
---|
720 | // set as "Seen" (read) |
---|
721 | $status = @imap_setflag_full($this->_mbox, $id, "\\Seen",ST_UID); |
---|
722 | } |
---|
723 | |
---|
724 | debugLog("IMAP-SetReadFlag -> set as " . (($flags) ? "read" : "unread") . "-->". $status); |
---|
725 | |
---|
726 | return $status; |
---|
727 | } |
---|
728 | |
---|
729 | /* This function is called when a message has been changed on the PDA. You should parse the new |
---|
730 | * message here and save the changes to disk. The return value must be whatever would be returned |
---|
731 | * from StatMessage() after the message has been saved. This means that both the 'flags' and the 'mod' |
---|
732 | * properties of the StatMessage() item may change via ChangeMessage(). |
---|
733 | * Note that this function will never be called on E-mail items as you can't change e-mail items, you |
---|
734 | * can only set them as 'read'. |
---|
735 | */ |
---|
736 | function ChangeMessage($folderid, $id, $message) { |
---|
737 | return false; |
---|
738 | } |
---|
739 | |
---|
740 | /* This function is called when the user moves an item on the PDA. You should do whatever is needed |
---|
741 | * to move the message on disk. After this call, StatMessage() and GetMessageList() should show the items |
---|
742 | * to have a new parent. This means that it will disappear from GetMessageList() will not return the item |
---|
743 | * at all on the source folder, and the destination folder will show the new message |
---|
744 | * |
---|
745 | */ |
---|
746 | function MoveMessage($folderid, $id, $newfolderid) { |
---|
747 | debugLog("IMAP-MoveMessage: (sfid: '$folderid' id: '$id' dfid: '$newfolderid' )"); |
---|
748 | |
---|
749 | $this->imap_reopenFolder($folderid); |
---|
750 | |
---|
751 | // read message flags |
---|
752 | $overview = @imap_fetch_overview ( $this->_mbox , $id, FT_UID); |
---|
753 | |
---|
754 | if (!$overview) { |
---|
755 | debugLog("IMAP-MoveMessage: Failed to retrieve overview"); |
---|
756 | return false; |
---|
757 | } |
---|
758 | else { |
---|
759 | // move message |
---|
760 | $s1 = imap_mail_move($this->_mbox, $id, str_replace(".", $this->_serverdelimiter, $newfolderid), FT_UID); |
---|
761 | |
---|
762 | // delete message in from-folder |
---|
763 | $s2 = imap_expunge($this->_mbox); |
---|
764 | |
---|
765 | // open new folder |
---|
766 | $this->imap_reopenFolder($newfolderid); |
---|
767 | |
---|
768 | // remove all flags |
---|
769 | $s3 = @imap_clearflag_full ($this->_mbox, $id, "\\Seen \\Answered \\Flagged \\Deleted \\Draft", FT_UID); |
---|
770 | $newflags = ""; |
---|
771 | if ($overview[0]->seen) $newflags .= "\\Seen"; |
---|
772 | if ($overview[0]->flagged) $newflags .= " \\Flagged"; |
---|
773 | if ($overview[0]->answered) $newflags .= " \\Answered"; |
---|
774 | $s4 = @imap_setflag_full ($this->_mbox, $id, $newflags, FT_UID); |
---|
775 | |
---|
776 | debugLog("MoveMessage: (" . $folderid . "->" . $newfolderid . ") s-move: $s1 s-expunge: $s2 unset-Flags: $s3 set-Flags: $s4"); |
---|
777 | |
---|
778 | return ($s1 && $s2 && $s3 && $s4); |
---|
779 | } |
---|
780 | } |
---|
781 | |
---|
782 | // new ping mechanism for the IMAP-Backend |
---|
783 | function AlterPing() { |
---|
784 | return true; |
---|
785 | } |
---|
786 | |
---|
787 | // returns a changes array using imap_status |
---|
788 | // if changes occurr default diff engine computes the actual changes |
---|
789 | function AlterPingChanges($folderid, &$syncstate) { |
---|
790 | debugLog("AlterPingChanges on $folderid stat: ". $syncstate); |
---|
791 | $this->imap_reopenFolder($folderid); |
---|
792 | |
---|
793 | // courier-imap only cleares the status cache after checking |
---|
794 | @imap_check($this->_mbox); |
---|
795 | |
---|
796 | $status = imap_status($this->_mbox, $this->_server . str_replace(".", $this->_serverdelimiter, $folderid), SA_ALL); |
---|
797 | if (!$status) { |
---|
798 | debugLog("AlterPingChanges: could not stat folder $folderid : ". imap_last_error()); |
---|
799 | return false; |
---|
800 | } |
---|
801 | else { |
---|
802 | $newstate = "M:". $status->messages ."-R:". $status->recent ."-U:". $status->unseen; |
---|
803 | |
---|
804 | // message number is different - change occured |
---|
805 | if ($syncstate != $newstate) { |
---|
806 | $syncstate = $newstate; |
---|
807 | debugLog("AlterPingChanges: Change FOUND!"); |
---|
808 | // build a dummy change |
---|
809 | return array(array("type" => "fakeChange")); |
---|
810 | } |
---|
811 | } |
---|
812 | |
---|
813 | return array(); |
---|
814 | } |
---|
815 | |
---|
816 | // ---------------------------------------- |
---|
817 | // imap-specific internals |
---|
818 | |
---|
819 | /* Parse the message and return only the plaintext body |
---|
820 | */ |
---|
821 | function getBody($message) { |
---|
822 | $body = ""; |
---|
823 | $htmlbody = ""; |
---|
824 | |
---|
825 | $this->getBodyRecursive($message, "plain", $body); |
---|
826 | |
---|
827 | if(!isset($body) or $body === '') { |
---|
828 | $this->getBodyRecursive($message, "html", $body); |
---|
829 | // remove css-style tags |
---|
830 | $body = preg_replace("/<style.*?<\/style>/is", "a", $body); |
---|
831 | // remove all other html |
---|
832 | //$body = strip_tags($body); |
---|
833 | |
---|
834 | // Remove the HTML tags using the 'html2text' - emerson-faria.nobre@serpro.gov.br |
---|
835 | // The 'html2text' (http://www.mbayer.de/html2text) must be installed in Z-Push server. |
---|
836 | |
---|
837 | // Advanced debug |
---|
838 | // debugLog("IMAP-getBody: subject: " . $message->headers["subject"]); |
---|
839 | $body = utf8_encode($body); |
---|
840 | libxml_use_internal_errors(true); |
---|
841 | try { |
---|
842 | $doc = new DOMDocument('1.0', 'UTF-8'); |
---|
843 | @$doc->loadHTML($body); |
---|
844 | $tables = $doc->getElementsByTagName('table'); |
---|
845 | foreach ($tables as $table) |
---|
846 | { |
---|
847 | $tds = $table->getElementsByTagName('td'); |
---|
848 | foreach ($tds as $td) |
---|
849 | { |
---|
850 | foreach ($td->childNodes as $td_child) { |
---|
851 | if ($td_child->nodeName == 'br') $td->removeChild($td_child); |
---|
852 | } |
---|
853 | } |
---|
854 | } |
---|
855 | $links = $doc->getElementsByTagName('a'); |
---|
856 | foreach ($links as $link) |
---|
857 | { |
---|
858 | if ($link->hasAttributes()){ |
---|
859 | $novoNo = $doc->createTextNode(' (' . $link->getAttribute('href') . ')'); |
---|
860 | $link->parentNode->insertBefore($novoNo, $link->nextSibling); |
---|
861 | } |
---|
862 | } |
---|
863 | $body = $doc->saveHTML(); |
---|
864 | } catch (Exception $e) { |
---|
865 | debugLog("IMAP-getBody: Alert - DOMDocument cannot parse HTML."); |
---|
866 | } |
---|
867 | $filename = "./state/" . $this->_user . "-" . $this->_devid . ".html"; |
---|
868 | $fp = fopen($filename, 'w') or die("can't open file"); |
---|
869 | fwrite($fp, $body); |
---|
870 | $body_aux = shell_exec('html2text -nobs -style compact "' . $filename . '"'); |
---|
871 | if (trim($body_aux) != '') $body = $body_aux; |
---|
872 | unset($body_aux); |
---|
873 | fclose($fp); |
---|
874 | unlink($filename); |
---|
875 | $body = utf8_decode($body); |
---|
876 | $body = str_replace('_','',$body); |
---|
877 | // End change block - Remove the HTML tags using the 'html2text' Linux application |
---|
878 | } |
---|
879 | return $body; |
---|
880 | } |
---|
881 | |
---|
882 | // Get all parts in the message with specified type and concatenate them together, unless the |
---|
883 | // Content-Disposition is 'attachment', in which case the text is apparently an attachment |
---|
884 | function getBodyRecursive($message, $subtype, &$body) { |
---|
885 | if(!isset($message->ctype_primary)) return; |
---|
886 | if(strcasecmp($message->ctype_primary,"text")==0 && strcasecmp($message->ctype_secondary,$subtype)==0 && isset($message->body)) |
---|
887 | $body .= $message->body; |
---|
888 | |
---|
889 | if(strcasecmp($message->ctype_primary,"multipart")==0 && isset($message->parts) && is_array($message->parts)) { |
---|
890 | foreach($message->parts as $part) { |
---|
891 | if(!isset($part->disposition) || strcasecmp($part->disposition,"attachment")) { |
---|
892 | $this->getBodyRecursive($part, $subtype, $body); |
---|
893 | } |
---|
894 | } |
---|
895 | } |
---|
896 | } |
---|
897 | |
---|
898 | // save the serverdelimiter for later folder (un)parsing |
---|
899 | function getServerDelimiter() { |
---|
900 | $list = @imap_getmailboxes($this->_mbox, $this->_server, "*"); |
---|
901 | if (is_array($list)) { |
---|
902 | $val = $list[0]; |
---|
903 | |
---|
904 | return $val->delimiter; |
---|
905 | } |
---|
906 | return "."; // default "." |
---|
907 | } |
---|
908 | |
---|
909 | // speed things up |
---|
910 | // remember what folder is currently open and only change if necessary |
---|
911 | function imap_reopenFolder($folderid, $force = false) { |
---|
912 | // to see changes, the folder has to be reopened! |
---|
913 | if ($this->_mboxFolder != $folderid || $force) { |
---|
914 | $s = @imap_reopen($this->_mbox, $this->_server . str_replace(".", $this->_serverdelimiter, $folderid)); |
---|
915 | if (!$s) debugLog("failed to change folder: ". implode(", ", imap_errors())); |
---|
916 | $this->_mboxFolder = $folderid; |
---|
917 | } |
---|
918 | } |
---|
919 | |
---|
920 | |
---|
921 | // build a multipart email, embedding body and one file (for attachments) |
---|
922 | function mail_attach($filenm,$filesize,$file_cont,$body, $body_ct, $body_cte) { |
---|
923 | |
---|
924 | $boundary = strtoupper(md5(uniqid(time()))); |
---|
925 | |
---|
926 | $mail_header = "Content-Type: multipart/mixed; boundary=$boundary\n"; |
---|
927 | |
---|
928 | // build main body with the sumitted type & encoding from the pda |
---|
929 | $mail_body = "This is a multi-part message in MIME format\n\n"; |
---|
930 | $mail_body .= "--$boundary\n"; |
---|
931 | $mail_body .= "Content-Type:$body_ct\n"; |
---|
932 | $mail_body .= "Content-Transfer-Encoding:$body_cte\n\n"; |
---|
933 | $mail_body .= "$body\n\n"; |
---|
934 | |
---|
935 | $mail_body .= "--$boundary\n"; |
---|
936 | $mail_body .= "Content-Type: text/plain; name=\"$filenm\"\n"; |
---|
937 | $mail_body .= "Content-Transfer-Encoding: base64\n"; |
---|
938 | $mail_body .= "Content-Disposition: attachment; filename=\"$filenm\"\n"; |
---|
939 | $mail_body .= "Content-Description: $filenm\n\n"; |
---|
940 | $mail_body .= base64_encode($file_cont) . "\n\n"; |
---|
941 | |
---|
942 | $mail_body .= "--$boundary--\n\n"; |
---|
943 | |
---|
944 | return array($mail_header, $mail_body); |
---|
945 | } |
---|
946 | |
---|
947 | // adds a message as seen to a specified folder (used for saving sent mails) |
---|
948 | function addSentMessage($folderid, $header, $body) { |
---|
949 | $header_body = str_replace("\n", "\r\n", str_replace("\r", "", $header . "\n\n" . $body)); |
---|
950 | |
---|
951 | return @imap_append($this->_mbox, $this->_server . $folderid, $header_body, "\\Seen"); |
---|
952 | } |
---|
953 | |
---|
954 | |
---|
955 | // parses address objects back to a simple "," separated string |
---|
956 | function parseAddr($ad) { |
---|
957 | $addr_string = ""; |
---|
958 | if (isset($ad) && is_array($ad)) { |
---|
959 | foreach($ad as $addr) { |
---|
960 | if ($addr_string) $addr_string .= ","; |
---|
961 | $addr_string .= $addr->mailbox . "@" . $addr->host; |
---|
962 | } |
---|
963 | } |
---|
964 | return $addr_string; |
---|
965 | } |
---|
966 | |
---|
967 | }; |
---|
968 | |
---|
969 | ?> |
---|