source: contrib/z-push/backend/imap.php @ 4903

Revision 4903, 43.9 KB checked in by thiagoaos, 13 years ago (diff)

Ticket #2192 - Adicionado configuração para definir nome da pasta Trash.

  • Property svn:executable set to *
Line 
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
16include_once('diffbackend.php');
17
18// The is an improved version of mimeDecode from PEAR that correctly
19// handles charsets and charset conversion
20include_once('mimeDecode.php');
21require_once('z_RFC822.php');
22
23class 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: for: $forward   reply: $reply   parent: $parent  RFC822:  \n". $rfc822 );
95
96                $mobj = new Mail_mimeDecode($rfc822);
97                $message = $mobj->decode(array('decode_headers' => false, 'decode_bodies' => true, 'include_bodies' => true, 'charset' => 'utf-8'));
98
99                $Mail_RFC822 = new Mail_RFC822();
100                $toaddr = $ccaddr = $bccaddr = "";
101                if(isset($message->headers["to"]))
102                        $toaddr = $this->parseAddr($Mail_RFC822->parseAddressList($message->headers["to"]));
103                if(isset($message->headers["cc"]))
104                        $ccaddr = $this->parseAddr($Mail_RFC822->parseAddressList($message->headers["cc"]));
105                if(isset($message->headers["bcc"]))
106                        $bccaddr = $this->parseAddr($Mail_RFC822->parseAddressList($message->headers["bcc"]));
107
108                // save some headers when forwarding mails (content type & transfer-encoding)
109                $headers = "";
110                $forward_h_ct = "";
111                $forward_h_cte = "";
112                $envelopefrom = "";
113
114                $use_orgbody = false;
115
116                // clean up the transmitted headers
117                // remove default headers because we are using imap_mail
118                $changedfrom = false;
119                $returnPathSet = false;
120                $body_base64 = false;
121                $org_charset = "";
122                $org_boundary = false;
123                $multipartmixed = false;
124               
125                foreach($message->headers as $k => $v) {
126                        if ($k == "subject" || $k == "to" || $k == "cc" || $k == "bcc")
127                                continue;
128
129                        if ($k == "content-type") {
130                                // if the message is a multipart message, then we should use the sent body
131                                if (preg_match("/multipart/i", $v)) {
132                                        $use_orgbody = true;
133                                        $org_boundary = $message->ctype_parameters["boundary"];
134                                }
135
136                                // save the original content-type header for the body part when forwarding
137                                if ($forward && !$use_orgbody) {
138                                        $forward_h_ct = $v;
139                                        continue;
140                                }
141
142                                // set charset always to utf-8
143                                $org_charset = $v;
144                                $v = preg_replace("/charset=([A-Za-z0-9-\"']+)/", "charset=\"utf-8\"", $v);
145                        }
146
147                        if ($k == "content-transfer-encoding") {
148                                // if the content was base64 encoded, encode the body again when sending
149                                if (trim($v) == "base64") $body_base64 = true;
150
151                                // save the original encoding header for the body part when forwarding
152                                if ($forward) {
153                                        $forward_h_cte = $v;
154                                        continue;
155                                }
156                        }
157
158                        // check if "from"-header is set, do nothing if it's set
159                        // else set it to IMAP_DEFAULTFROM
160                        if ($k == "from") {
161                                if (trim($v)) {
162                                        $changedfrom = true;
163                                } elseif (! trim($v) && IMAP_DEFAULTFROM) {
164                                        $changedfrom = true;
165                                        if      (IMAP_DEFAULTFROM == 'username') $v = $this->_username;
166                                        else if (IMAP_DEFAULTFROM == 'domain')   $v = $this->_domain;
167                                        else $v = $this->_username . IMAP_DEFAULTFROM;
168                                        $envelopefrom = "-f$v";
169                                }
170                        }
171
172                        // check if "Return-Path"-header is set
173                        if ($k == "return-path") {
174                                $returnPathSet = true;
175                                if (! trim($v) && IMAP_DEFAULTFROM) {
176                                        if      (IMAP_DEFAULTFROM == 'username') $v = $this->_username;
177                                        else if (IMAP_DEFAULTFROM == 'domain')   $v = $this->_domain;
178                                        else $v = $this->_username . IMAP_DEFAULTFROM;
179                                }
180                        }
181
182                        // all other headers stay
183                        if ($headers) $headers .= "\n";
184                        $headers .= ucfirst($k) . ": ". $v;
185                }
186
187                // set "From" header if not set on the device
188                if(IMAP_DEFAULTFROM && !$changedfrom){
189                        if      (IMAP_DEFAULTFROM == 'username') $v = $this->_username;
190                        else if (IMAP_DEFAULTFROM == 'domain')   $v = $this->_domain;
191                        else $v = $this->_username . IMAP_DEFAULTFROM;
192                        if ($headers) $headers .= "\n";
193                        $headers .= 'From: '.$v;
194                        $envelopefrom = "-f$v";
195                }
196
197                // set "Return-Path" header if not set on the device
198                if(IMAP_DEFAULTFROM && !$returnPathSet){
199                        if      (IMAP_DEFAULTFROM == 'username') $v = $this->_username;
200                        else if (IMAP_DEFAULTFROM == 'domain')   $v = $this->_domain;
201                        else $v = $this->_username . IMAP_DEFAULTFROM;
202                        if ($headers) $headers .= "\n";
203                        $headers .= 'Return-Path: '.$v;
204                }
205
206                // if this is a multipart message with a boundary, we must use the original body
207                if ($use_orgbody) {
208                        list(,$body) = $mobj->_splitBodyHeader($rfc822);
209                        $repl_body = $this->getBody($message);
210                        if ($message->parts[0]->headers["content-transfer-encoding"] == "base64") $multipart_text_cte_base64 = true;
211                        else $multipart_text_cte_base64 = false;
212                }
213                else
214                        $body = $this->getBody($message);
215
216                // reply
217                if ($reply && $parent) {
218                        $this->imap_reopenFolder($parent);
219                        // receive entire mail (header + body) to decode body correctly
220                        $origmail = @imap_fetchheader($this->_mbox, $reply, FT_UID) . @imap_body($this->_mbox, $reply, FT_PEEK | FT_UID);
221
222                        $mobj2 = new Mail_mimeDecode($origmail);
223                        // receive only body
224                        $body .= $this->getBody($mobj2->decode(array('decode_headers' => false, 'decode_bodies' => true, 'include_bodies' => true, 'charset' => 'utf-8')));
225                        // unset mimedecoder & origmail - free memory
226                        unset($mobj2);
227                        unset($origmail);
228                }
229
230                // encode the body to base64 if it was sent originally in base64 by the pda
231                // contrib - chunk base64 encoded body
232                if ($body_base64 && !$forward) $body = chunk_split(base64_encode($body));
233
234
235                // forward
236                if ($forward && $parent) {
237                        $this->imap_reopenFolder($parent);
238                        // receive entire mail (header + body)
239                        $origmail = @imap_fetchheader($this->_mbox, $forward, FT_UID) . @imap_body($this->_mbox, $forward, FT_PEEK | FT_UID);
240
241                                if (defined('IMAP_INLINE_FORWARD') && IMAP_INLINE_FORWARD === false) {
242                                        // contrib - chunk base64 encoded body
243                                        if ($body_base64) $body = chunk_split(base64_encode($body));
244                                        //use original boundary if it's set
245                                        $boundary = ($org_boundary) ? $org_boundary : false;
246                                        // build a new mime message, forward entire old mail as file
247                                        list($aheader, $body) = $this->mail_attach("forwarded_message.eml",strlen($origmail),$origmail, $body, $forward_h_ct, $forward_h_cte,$boundary);
248                                        // add boundary headers
249                                        $headers .= "\n" . $aheader;
250                                }
251                                else {
252                                        $mobj2 = new Mail_mimeDecode($origmail);
253                                        $mess2 = $mobj2->decode(array('decode_headers' => true, 'decode_bodies' => true, 'include_bodies' => true, 'charset' => 'utf-8'));
254
255                                        if (!$use_orgbody)
256                                                $nbody = $body;
257                                        else
258                                                $nbody = $repl_body;
259
260                                        $nbody .= "\r\n\r\n";
261                                        $nbody .= "-----Original Message-----\r\n";
262                                        if(isset($mess2->headers['from']))
263                                                $nbody .= "From: " . $mess2->headers['from'] . "\r\n";
264                                        if(isset($mess2->headers['to']) && strlen($mess2->headers['to']) > 0)
265                                                $nbody .= "To: " . $mess2->headers['to'] . "\r\n";
266                                        if(isset($mess2->headers['cc']) && strlen($mess2->headers['cc']) > 0)
267                                                $nbody .= "Cc: " . $mess2->headers['cc'] . "\r\n";
268                                        if(isset($mess2->headers['date']))
269                                                $nbody .= "Sent: " . $mess2->headers['date'] . "\r\n";
270                                        if(isset($mess2->headers['subject']))
271                                                $nbody .= "Subject: " . $mess2->headers['subject'] . "\r\n";
272                                       
273                                        $nbody .= "\r\n";
274                                        $nbody .= $this->getBody($mess2);
275
276                                        if ($body_base64) {
277                                                // contrib - chunk base64 encoded body
278                                                $nbody = chunk_split(base64_encode($nbody));
279                                                if ($use_orgbody)
280                                                        // contrib - chunk base64 encoded body
281                                                        $repl_body = chunk_split(base64_encode($repl_body));
282                                        }
283
284                                        if ($use_orgbody) {
285                                                debugLog("-------------------");
286                                                debugLog("old:\n'$repl_body'\nnew:\n'$nbody'\nund der body:\n'$body'");
287                                                //$body is quoted-printable encoded while $repl_body and $nbody are plain text,
288                                                //so we need to decode $body in order replace to take place
289                                                if (!$multipart_text_cte_base64) {
290                                                        $body = str_replace($repl_body, $nbody, quoted_printable_decode($body));
291                                                } else {
292                                                        $body = str_replace(base64_encode($repl_body), base64_encode($nbody), $body);                   
293                                                }
294                                        }
295                                        else
296                                                $body = $nbody;
297
298
299                                        if(isset($mess2->parts)) {
300                                                $attached = false;
301
302                                                if ($org_boundary) {
303                                                        $att_boundary = $org_boundary;
304                                                        // cut end boundary from body
305                                                        $body = substr($body, 0, strrpos($body, "--$att_boundary--"));
306                                                }
307                                                else {
308                                                        $att_boundary = strtoupper(md5(uniqid(time())));
309                                                        // add boundary headers
310                                                        $headers .= "\n" . "Content-Type: multipart/mixed; boundary=$att_boundary";
311                                                        $multipartmixed = true;
312                                                }
313
314                                                foreach($mess2->parts as $part) {
315                                                        if(isset($part->disposition) && ($part->disposition == "attachment" || $part->disposition == "inline")) {
316
317                                                        if(isset($part->d_parameters['filename']))
318                                                                $attname = $part->d_parameters['filename'];
319                                                        else if(isset($part->ctype_parameters['name']))
320                                                                $attname = $part->ctype_parameters['name'];
321                                                        else if(isset($part->headers['content-description']))
322                                                                $attname = $part->headers['content-description'];
323                                                        else $attname = "unknown attachment";
324
325                                                        // ignore html content
326                                                        if ($part->ctype_primary == "text" && $part->ctype_secondary == "html") {
327                                                                continue;
328                                                        }
329                                                        //
330                                                        if ($use_orgbody || $attached) {
331                                                                $body .= $this->enc_attach_file($att_boundary, $attname, strlen($part->body),$part->body, $part->ctype_primary ."/". $part->ctype_secondary);
332                                                        }
333                                                        // first attachment
334                                                        else {
335                                                                $encmail = $body;
336                                                                $attached = true;
337                                                                $body = $this->enc_multipart($att_boundary, $body, $forward_h_ct, $forward_h_cte);
338                                                                $body .= $this->enc_attach_file($att_boundary, $attname, strlen($part->body),$part->body, $part->ctype_primary ."/". $part->ctype_secondary);
339                                                        }
340                                                }
341                                        }
342                                        if ($multipartmixed) {
343                                                //this happens if a multipart/alternative message is forwarded
344                                                //then it's a multipart/mixed message which consists of:
345                                                //1. text/plain part which was written on the mobile
346                                                //2. multipart/alternative part which is the original message
347                                                //$body = "This is a message with multiple parts in MIME format.\n--".
348                                                //        $att_boundary.
349                                                //        "\nContent-Type: $forward_h_ct\nContent-Transfer-Encoding: $forward_h_cte\n\n".
350                                                //        (($body_base64) ? chunk_split(base64_encode($message->body)) : rtrim($message->body)).
351                                                //        "\n--".$att_boundary.
352                                                //        "\nContent-Type: {$mess2->headers['content-type']}\n\n".
353                                                //        @imap_body($this->_mbox, $forward, FT_PEEK | FT_UID)."\n\n";
354                                                $body = "\n--".
355                                                        $att_boundary.
356                                                        "\nContent-Type: $forward_h_ct\nContent-Transfer-Encoding: $forward_h_cte\n\n".
357                                                        $body;
358                                        }
359
360                                        $body .= "--$att_boundary--\n\n";
361                                }
362
363                                unset($mobj2);
364                        }
365
366                        // unset origmail - free memory
367                        unset($origmail);
368
369                }
370
371                // remove carriage-returns from body
372                $body = str_replace("\r\n", "\n", $body);
373
374                if (!$multipartmixed) {
375                        if (!empty($forward_h_ct)) $headers .= "\nContent-Type: $forward_h_ct";
376                        if (!empty($forward_h_cte)) $headers .= "\nContent-Transfer-Encoding: $forward_h_cte";
377                }
378                //advanced debugging
379                debugLog("IMAP-SendMail: parsed message: ". print_r($message,1));
380                debugLog("IMAP-SendMail: headers: $headers");
381                debugLog("IMAP-SendMail: subject: {$message->headers["subject"]}");
382                debugLog("IMAP-SendMail: body: $body");
383
384                if (!defined('IMAP_USE_IMAPMAIL') || IMAP_USE_IMAPMAIL == true) {
385                        $send =  @imap_mail ( $toaddr, $message->headers["subject"], $body, $headers, $ccaddr, $bccaddr);
386                }
387                else {
388                        if (!empty($ccaddr))  $headers .= "\nCc: $ccaddr";
389                        if (!empty($bccaddr)) $headers .= "\nBcc: $bccaddr";
390                        $send =  @mail ( $toaddr, $message->headers["subject"], $body, $headers, $envelopefrom );
391                }
392
393                // email sent?
394                if (!$send) {
395                        debugLog("The email could not be sent. Last-IMAP-error: ". imap_last_error());
396                }
397
398                // add message to the sent folder
399                // build complete headers
400                $headers .= "\nTo: $toaddr";
401                $headers .= "\nSubject: " . $message->headers["subject"];
402
403                if (!defined('IMAP_USE_IMAPMAIL') || IMAP_USE_IMAPMAIL == true) {
404                        if (!empty($ccaddr))  $headers .= "\nCc: $ccaddr";
405                        if (!empty($bccaddr)) $headers .= "\nBcc: $bccaddr";
406                }
407                debugLog("IMAP-SendMail: complete headers: $headers");
408
409                $asf = false;
410                if ($this->_sentID) {
411                        $asf = $this->addSentMessage($this->_sentID, $headers, $body);
412                }
413                else if(defined("IMAP_SENTFOLDER")) {
414                        $asf = $this->addSentMessage(IMAP_SENTFOLDER, $headers, $body);
415                        debugLog("IMAP-SendMail: Outgoing mail saved in configured 'Sent' folder '".IMAP_SENTFOLDER."': ". (($asf)?"success":"failed"));
416                }
417                // No Sent folder set, try defaults
418                else {
419                        debugLog("IMAP-SendMail: No Sent mailbox set");
420                        if($this->addSentMessage("INBOX.Sent", $headers, $body)) {
421                                debugLog("IMAP-SendMail: Outgoing mail saved in 'INBOX.Sent'");
422                                $asf = true;
423                        }
424                        else if ($this->addSentMessage("Sent", $headers, $body)) {
425                                debugLog("IMAP-SendMail: Outgoing mail saved in 'Sent'");
426                                $asf = true;
427                        }
428                        else if ($this->addSentMessage("Sent Items", $headers, $body)) {
429                                debugLog("IMAP-SendMail: Outgoing mail saved in 'Sent Items'");
430                                $asf = true;
431                        }
432                }
433
434                // unset mimedecoder - free memory
435                unset($mobj);
436                return ($send && $asf);
437        }
438
439        /* Should return a wastebasket folder if there is one. This is used when deleting
440         * items; if this function returns a valid folder ID, then all deletes are handled
441         * as moves and are sent to your backend as a move. If it returns FALSE, then deletes
442         * are always handled as real deletes and will be sent to your importer as a DELETE
443         */
444        function GetWasteBasket() {
445                return $this->_wasteID;
446        }
447
448        /* Should return a list (array) of messages, each entry being an associative array
449         * with the same entries as StatMessage(). This function should return stable information; ie
450         * if nothing has changed, the items in the array must be exactly the same. The order of
451         * the items within the array is not important though.
452         *
453         * The cutoffdate is a date in the past, representing the date since which items should be shown.
454         * This cutoffdate is determined by the user's setting of getting 'Last 3 days' of e-mail, etc. If
455         * you ignore the cutoffdate, the user will not be able to select their own cutoffdate, but all
456         * will work OK apart from that.
457         */
458
459        function GetMessageList($folderid, $cutoffdate) {
460                debugLog("IMAP-GetMessageList: (fid: '$folderid'  cutdate: '$cutoffdate' )");
461
462                $messages = array();
463                $this->imap_reopenFolder($folderid, true);
464
465                $sequence = "1:*";
466                if ($cutoffdate > 0) {
467                        $search = @imap_search($this->_mbox, "SINCE ". date("d-M-Y", $cutoffdate));
468                        if ($search !== false)
469                        $sequence = implode(",", $search);
470                        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);
471                }
472
473                $overviews = @imap_fetch_overview($this->_mbox, $sequence);
474
475                if (!$overviews) {
476                        debugLog("IMAP-GetMessageList: Failed to retrieve overview");
477                } else {
478                        foreach($overviews as $overview) {
479                                $date = "";
480                                $vars = get_object_vars($overview);
481                                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));
482                                if (array_key_exists( "date", $vars)) {
483                                        // message is out of range for cutoffdate, ignore it
484                                        if(strtotime(preg_replace("/\(.*\)/", "", $overview->date)) < $cutoffdate) { // emerson-faria.nobre@serpro.gov.br - 07/feb/2011
485                                                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.');
486                                                continue;
487                                        }
488                                        //if(strtotime($overview->date) < $cutoffdate) continue;
489                                        $date = $overview->date;
490                                } 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.');
491
492                                // cut of deleted messages
493                                if (array_key_exists( "deleted", $vars) && $overview->deleted) {
494                                        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');
495                                continue;
496                                }
497
498                                if (array_key_exists( "uid", $vars)) {
499                                        $message = array();
500                                        $message["mod"] = $date;
501                                        $message["id"] = $overview->uid;
502                                        // 'seen' aka 'read' is the only flag we want to know about
503                                        $message["flags"] = 0;
504
505                                        if(array_key_exists( "seen", $vars) && $overview->seen)
506                                        $message["flags"] = 1;
507                                        array_push($messages, $message);
508                                } 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.');
509                                }
510                        }
511                return $messages;
512        }
513
514        /* This function is analogous to GetMessageList.
515         *
516         */
517        function GetFolderList() {
518                $folders = array();
519
520                $list = @imap_getmailboxes($this->_mbox, $this->_server, "*");
521                if (is_array($list)) {
522                        // reverse list to obtain folders in right order
523                        $list = array_reverse($list);
524                        foreach ($list as $val) {
525                                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));
526                                $box = array();
527
528                                // cut off serverstring
529                                $box["id"] = imap_utf7_decode(substr($val->name, strlen($this->_server)));
530
531                                // always use "." as folder delimiter
532                                $box["id"] = imap_utf7_encode(str_replace($val->delimiter, ".", $box["id"]));
533
534                                // explode hierarchies
535                                $fhir = explode(".", $box["id"]);
536                                if (count($fhir) > 1) {
537                                        $box["mod"] = imap_utf7_encode(array_pop($fhir)); // mod is last part of path
538                                        $box["parent"] = imap_utf7_encode(implode(".", $fhir)); // parent is all previous parts of path
539                                }
540                                else {
541                                        $box["mod"] = imap_utf7_encode($box["id"]);
542                                        $box["parent"] = "0";
543                                }
544                                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));
545                                $folders[]=$box;
546                        }
547                }
548                else {
549                        debugLog("GetFolderList: imap_list failed: " . imap_last_error());
550                }
551
552                return $folders;
553        }
554
555        /* GetFolder should return an actual SyncFolder object with all the properties set. Folders
556         * are pretty simple really, having only a type, a name, a parent and a server ID.
557         */
558
559        function GetFolder($id) {
560                $folder = new SyncFolder();
561                $folder->serverid = $id;
562
563                // explode hierarchy
564                $fhir = explode(".", $id);
565
566                // compare on lowercase strings
567                $lid = strtolower($id);
568
569                $trash_folder_name = 'inbox.trash';
570
571                if(defined("IMAP_TRASHFOLDER"))
572                        $trash_folder_name = strtolower(str_replace($this->_serverdelimiter, ".", IMAP_TRASHFOLDER));
573
574                $sent_folder_name = 'inbox.sent';
575
576                if(defined("IMAP_SENTFOLDER"))
577                        $sent_folder_name = strtolower(str_replace($this->_serverdelimiter, ".", IMAP_SENTFOLDER));
578
579                $folder->parentid =  (($fhir && count($fhir) > 1) ? $fhir[(count($fhir) - 2)] : "0");
580
581                if($lid == "inbox") {
582                        $folder->parentid = "0"; // Root
583                        $folder->displayname = "Inbox";
584                        $folder->type = SYNC_FOLDER_TYPE_INBOX;
585                }
586                // Zarafa IMAP-Gateway outputs
587                else if($lid == "drafts" || $lid == "inbox.drafts" || $lid == "inbox.rascunhos") {
588                        $folder->displayname = "Drafts";
589                        $folder->type = SYNC_FOLDER_TYPE_DRAFTS;
590                }
591                else if($lid == "trash" || $lid == $trash_folder_name) {
592                        $folder->displayname = (defined("IMAP_DISPLAYNAME_TRASHFOLDER") ? IMAP_DISPLAYNAME_TRASHFOLDER : "Trash");
593                        $folder->type = SYNC_FOLDER_TYPE_WASTEBASKET;
594                        $this->_wasteID = $id;
595                }
596                else if($lid == "sent" || $lid == "sent items" || $lid == $sent_folder_name) {
597                        $folder->displayname = (defined("IMAP_DISPLAYNAME_SENTFOLDER") ? IMAP_DISPLAYNAME_SENTFOLDER : "Sent");
598                        $folder->type = SYNC_FOLDER_TYPE_SENTMAIL;
599                        $this->_sentID = $id;
600                }
601                // define the rest as other-folders
602                else {
603                        if (count($fhir) > 1) {
604                                $folder->displayname = windows1252_to_utf8(imap_utf7_decode(array_pop($fhir)));
605                                $folder->parentid = implode(".", $fhir);
606                        }
607                        else {
608                                $folder->displayname = windows1252_to_utf8(imap_utf7_decode($id));
609                                $folder->parentid = "0";
610                        }
611                        $folder->type = SYNC_FOLDER_TYPE_OTHER;
612                }
613
614                //advanced debugging
615                //debugLog("IMAP-GetFolder(id: '$id') -> " . print_r($folder, 1));
616                if (TRACE_UID !== false and (TRACE_TYPE == 'IMAP' or TRACE_TYPE == 'ALL')) traceLog('IMAP::GetFolder(id: '.$id.'): '.print_r($folder,1));
617
618                return $folder;
619        }
620
621        /* Return folder stats. This means you must return an associative array with the
622         * following properties:
623         * "id" => The server ID that will be used to identify the folder. It must be unique, and not too long
624         *         How long exactly is not known, but try keeping it under 20 chars or so. It must be a string.
625         * "parent" => The server ID of the parent of the folder. Same restrictions as 'id' apply.
626         * "mod" => This is the modification signature. It is any arbitrary string which is constant as long as
627         *          the folder has not changed. In practice this means that 'mod' can be equal to the folder name
628         *          as this is the only thing that ever changes in folders. (the type is normally constant)
629         */
630        function StatFolder($id) {
631                $folder = $this->GetFolder($id);
632
633                $stat = array();
634                $stat["id"] = $id;
635                $stat["parent"] = $folder->parentid;
636                $stat["mod"] = $folder->displayname;
637                if (TRACE_UID !== false and (TRACE_TYPE == 'IMAP' or TRACE_TYPE == 'ALL')) traceLog('IMAP::StatFolder(id: '.$id.'): '.print_r($stat,1));
638                return $stat;
639        }
640
641        /* Creates or modifies a folder
642         * "folderid" => id of the parent folder
643         * "oldid" => if empty -> new folder created, else folder is to be renamed
644         * "displayname" => new folder name (to be created, or to be renamed to)
645         * "type" => folder type, ignored in IMAP
646         *
647         */
648        function ChangeFolder($folderid, $oldid, $displayname, $type){
649                debugLog("ChangeFolder: (parent: '$folderid'  oldid: '$oldid'  displayname: '$displayname'  type: '$type')");
650
651                // go to parent mailbox
652                $this->imap_reopenFolder($folderid);
653
654                // build name for new mailbox
655                $newname = $this->_server . str_replace(".", $this->_serverdelimiter, $folderid) . $this->_serverdelimiter . $displayname;
656
657                $csts = false;
658                // if $id is set => rename mailbox, otherwise create
659                if ($oldid) {
660                        // rename doesn't work properly with IMAP
661                        // the activesync client doesn't support a 'changing ID'
662                        //$csts = imap_renamemailbox($this->_mbox, $this->_server . imap_utf7_encode(str_replace(".", $this->_serverdelimiter, $oldid)), $newname);
663                }
664                else {
665                        $csts = @imap_createmailbox($this->_mbox, $newname);
666                }
667                if ($csts) {
668                        return $this->StatFolder($folderid . "." . $displayname);
669                }
670                else
671                return false;
672        }
673
674        /* Should return attachment data for the specified attachment. The passed attachment identifier is
675         * the exact string that is returned in the 'AttName' property of an SyncAttachment. So, you should
676         * encode any information you need to find the attachment in that 'attname' property.
677         */
678        function GetAttachmentData($attname) {
679                debugLog("getAttachmentDate: (attname: '$attname')");
680
681                list($folderid, $id, $part) = explode(":", $attname);
682
683                $this->imap_reopenFolder($folderid);
684                $mail = @imap_fetchheader($this->_mbox, $id, FT_PREFETCHTEXT | FT_UID) . @imap_body($this->_mbox, $id, FT_PEEK | FT_UID);
685
686                $mobj = new Mail_mimeDecode($mail);
687                $message = $mobj->decode(array('decode_headers' => true, 'decode_bodies' => true, 'include_bodies' => true, 'input' => $mail, 'crlf' => "\n", 'charset' => 'utf-8'));
688
689                if (isset($message->parts[$part]->body))
690                print $message->parts[$part]->body;
691
692                // unset mimedecoder & mail
693                unset($mobj);
694                unset($mail);
695                return true;
696        }
697
698        /* StatMessage should return message stats, analogous to the folder stats (StatFolder). Entries are:
699         * 'id'     => Server unique identifier for the message. Again, try to keep this short (under 20 chars)
700         * 'flags'     => simply '0' for unread, '1' for read
701         * 'mod'    => modification signature. As soon as this signature changes, the item is assumed to be completely
702         *             changed, and will be sent to the PDA as a whole. Normally you can use something like the modification
703         *             time for this field, which will change as soon as the contents have changed.
704         */
705
706        function StatMessage($folderid, $id) {
707                debugLog("IMAP-StatMessage: (fid: '$folderid'  id: '$id' )");
708
709                $this->imap_reopenFolder($folderid);
710                $overview = @imap_fetch_overview( $this->_mbox , $id , FT_UID);
711
712                if (!$overview) {
713                        debugLog("IMAP-StatMessage: Failed to retrieve overview: ". imap_last_error());
714                        return false;
715                }
716
717                else {
718                        // check if variables for this overview object are available
719                        $vars = get_object_vars($overview[0]);
720
721                        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"');
722                        // without uid it's not a valid message
723                        if (! array_key_exists( "uid", $vars)) return false;
724
725
726                        $entry = array();
727                        $entry["mod"] = (array_key_exists( "date", $vars)) ? $overview[0]->date : "";
728                        $entry["id"] = $overview[0]->uid;
729                        // 'seen' aka 'read' is the only flag we want to know about
730                        $entry["flags"] = 0;
731
732                        if(array_key_exists( "seen", $vars) && $overview[0]->seen)
733                        $entry["flags"] = 1;
734
735                        if (TRACE_UID !== false and (TRACE_TYPE == 'IMAP' or TRACE_TYPE == 'ALL')) traceLog('IMAP::StatMessage: '.print_r($entry,1));
736
737                        //advanced debugging
738                        //debugLog("IMAP-StatMessage-parsed: ". print_r($entry,1));
739
740                        return $entry;
741                }
742        }
743
744        /* GetMessage should return the actual SyncXXX object type. You may or may not use the '$folderid' parent folder
745         * identifier here.
746         * Note that mixing item types is illegal and will be blocked by the engine; ie returning an Email object in a
747         * Tasks folder will not do anything. The SyncXXX objects should be filled with as much information as possible,
748         * but at least the subject, body, to, from, etc.
749         */
750        function GetMessage($folderid, $id, $truncsize, $mimesupport = 0) {
751                debugLog("IMAP-GetMessage: (fid: '$folderid'  id: '$id'  truncsize: $truncsize)");
752
753                // Get flags, etc
754                $stat = $this->StatMessage($folderid, $id);
755
756                if ($stat) {
757                        $this->imap_reopenFolder($folderid);
758                        $mail = @imap_fetchheader($this->_mbox, $id, FT_PREFETCHTEXT | FT_UID) . @imap_body($this->_mbox, $id, FT_PEEK | FT_UID);
759
760                        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));
761
762                        $mobj = new Mail_mimeDecode($mail);
763                        $message = $mobj->decode(array('decode_headers' => true, 'decode_bodies' => true, 'include_bodies' => true, 'input' => $mail, 'crlf' => "\n", 'charset' => 'utf-8'));
764
765                        if (TRACE_UID !== false and (TRACE_TYPE == 'IMAP' or TRACE_TYPE == 'ALL')) traceLog("IMAP-GetMessage: Mensagem mime decodificada: ". print_r($message,1));
766
767                        $output = new SyncMail();
768
769                        $body = $this->getBody($message, true); // true - Truncate body due to celular memory limit
770                        // truncate body, if requested
771                        if(strlen($body) > $truncsize) {
772                                $body = utf8_truncate($body, $truncsize);
773                                $output->bodytruncated = 1;
774                        } else {
775                                $body = $body;
776                                $output->bodytruncated = 0;
777                        }
778                        $body = str_replace("\n","\r\n", str_replace("\r","",$body));
779
780                        $output->bodysize = strlen($body);
781                        $output->body = $body;
782                        //$output->datereceived = isset($message->headers["date"]) ? strtotime($message->headers["date"]) : null;
783                        $output->datereceived = isset($message->headers["date"]) ? strtotime(preg_replace("/\(.*\)/", "", $message->headers["date"])) : null; // emerson-faria.nobre@serpro.gov.br
784                        $output->displayto = isset($message->headers["to"]) ? $message->headers["to"] : null;
785                        $output->importance = isset($message->headers["x-priority"]) ? preg_replace("/\D+/", "", $message->headers["x-priority"]) : null;
786                        $output->messageclass = "IPM.Note";
787                        $output->subject = isset($message->headers["subject"]) ? $message->headers["subject"] : "";
788                        $output->read = $stat["flags"];
789                        $output->to = isset($message->headers["to"]) ? $message->headers["to"] : null;
790                        $output->cc = isset($message->headers["cc"]) ? $message->headers["cc"] : null;
791                        $output->from = isset($message->headers["from"]) ? $message->headers["from"] : null;
792                        $output->reply_to = isset($message->headers["reply-to"]) ? $message->headers["reply-to"] : null;
793
794                        // Attachments are only searched in the top-level part
795                        $n = 0;
796                        if(isset($message->parts)) {
797                                foreach($message->parts as $part) {
798                                        if(isset($part->disposition) && ($part->disposition == "attachment" || $part->disposition == "inline")) {
799                                                $attachment = new SyncAttachment();
800
801                                                if (isset($part->body))
802                                                $attachment->attsize = strlen($part->body);
803
804                                                if(isset($part->d_parameters['filename']))
805                                                $attname = $part->d_parameters['filename'];
806                                                else if(isset($part->ctype_parameters['name']))
807                                                $attname = $part->ctype_parameters['name'];
808                                                else if(isset($part->headers['content-description']))
809                                                $attname = $part->headers['content-description'];
810                                                else $attname = "unknown attachment";
811
812                                                $attachment->displayname = $attname;
813                                                $attachment->attname = $folderid . ":" . $id . ":" . $n;
814                                                $attachment->attmethod = 1;
815                                                $attachment->attoid = isset($part->headers['content-id']) ? $part->headers['content-id'] : "";
816                                                array_push($output->attachments, $attachment);
817                                        }
818                                        $n++;
819                                }
820                        }
821                        // unset mimedecoder & mail
822                        unset($mobj);
823                        unset($mail);
824                        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));
825                        return $output;
826                }
827                return false;
828        }
829
830        /* This function is called when the user has requested to delete (really delete) a message. Usually
831         * this means just unlinking the file its in or somesuch. After this call has succeeded, a call to
832         * GetMessageList() should no longer list the message. If it does, the message will be re-sent to the PDA
833         * as it will be seen as a 'new' item. This means that if you don't implement this function, you will
834         * be able to delete messages on the PDA, but as soon as you sync, you'll get the item back
835         */
836        function DeleteMessage($folderid, $id) {
837                debugLog("IMAP-DeleteMessage: (fid: '$folderid'  id: '$id' )");
838
839                $this->imap_reopenFolder($folderid);
840                $s1 = @imap_delete ($this->_mbox, $id, FT_UID);
841                $s11 = @imap_setflag_full($this->_mbox, $id, "\\Deleted", FT_UID);
842                $s2 = @imap_expunge($this->_mbox);
843
844                debugLog("IMAP-DeleteMessage: s-delete: $s1   s-expunge: $s2    setflag: $s11");
845
846                return ($s1 && $s2 && $s11);
847        }
848
849        /* This should change the 'read' flag of a message on disk. The $flags
850         * parameter can only be '1' (read) or '0' (unread). After a call to
851         * SetReadFlag(), GetMessageList() should return the message with the
852         * new 'flags' but should not modify the 'mod' parameter. If you do
853         * change 'mod', simply setting the message to 'read' on the PDA will trigger
854         * a full resync of the item from the server
855         */
856        function SetReadFlag($folderid, $id, $flags) {
857                debugLog("IMAP-SetReadFlag: (fid: '$folderid'  id: '$id'  flags: '$flags' )");
858
859                $this->imap_reopenFolder($folderid);
860
861                if ($flags == 0) {
862                        // set as "Unseen" (unread)
863                        $status = @imap_clearflag_full ( $this->_mbox, $id, "\\Seen", ST_UID);
864                } else {
865                        // set as "Seen" (read)
866                        $status = @imap_setflag_full($this->_mbox, $id, "\\Seen",ST_UID);
867                }
868
869                debugLog("IMAP-SetReadFlag -> set as " . (($flags) ? "read" : "unread") . "-->". $status);
870
871                return $status;
872        }
873
874        /* This function is called when a message has been changed on the PDA. You should parse the new
875         * message here and save the changes to disk. The return value must be whatever would be returned
876         * from StatMessage() after the message has been saved. This means that both the 'flags' and the 'mod'
877         * properties of the StatMessage() item may change via ChangeMessage().
878         * Note that this function will never be called on E-mail items as you can't change e-mail items, you
879         * can only set them as 'read'.
880         */
881        function ChangeMessage($folderid, $id, $message) {
882                return false;
883        }
884
885        /* This function is called when the user moves an item on the PDA. You should do whatever is needed
886         * to move the message on disk. After this call, StatMessage() and GetMessageList() should show the items
887         * to have a new parent. This means that it will disappear from GetMessageList() will not return the item
888         * at all on the source folder, and the destination folder will show the new message
889         *
890         */
891        function MoveMessage($folderid, $id, $newfolderid) {
892                debugLog("IMAP-MoveMessage: (sfid: '$folderid'  id: '$id'  dfid: '$newfolderid' )");
893
894                $this->imap_reopenFolder($folderid);
895
896                // read message flags
897                $overview = @imap_fetch_overview ( $this->_mbox , $id, FT_UID);
898
899                if (!$overview) {
900                        debugLog("IMAP-MoveMessage: Failed to retrieve overview");
901                        return false;
902                }
903                else {
904                        // move message
905                        $s1 = imap_mail_move($this->_mbox, $id, str_replace(".", $this->_serverdelimiter, $newfolderid), FT_UID);
906
907                        // delete message in from-folder
908                        $s2 = imap_expunge($this->_mbox);
909
910                        // open new folder
911                        $this->imap_reopenFolder($newfolderid);
912
913                        // remove all flags
914                        $s3 = @imap_clearflag_full ($this->_mbox, $id, "\\Seen \\Answered \\Flagged \\Deleted \\Draft", FT_UID);
915                        $newflags = "";
916                        if ($overview[0]->seen) $newflags .= "\\Seen";
917                        if ($overview[0]->flagged) $newflags .= " \\Flagged";
918                        if ($overview[0]->answered) $newflags .= " \\Answered";
919                        $s4 = @imap_setflag_full ($this->_mbox, $id, $newflags, FT_UID);
920
921                        debugLog("MoveMessage: (" . $folderid . "->" . $newfolderid . ") s-move: $s1   s-expunge: $s2    unset-Flags: $s3    set-Flags: $s4");
922
923                        return ($s1 && $s2 && $s3 && $s4);
924                }
925        }
926
927        // new ping mechanism for the IMAP-Backend
928        function AlterPing() {
929                return true;
930        }
931
932        // returns a changes array using imap_status
933        // if changes occurr default diff engine computes the actual changes
934        function AlterPingChanges($folderid, &$syncstate) {
935                debugLog("AlterPingChanges on $folderid stat: ". $syncstate);
936                $this->imap_reopenFolder($folderid);
937
938                // courier-imap only cleares the status cache after checking
939                @imap_check($this->_mbox);
940
941                $status = imap_status($this->_mbox, $this->_server . str_replace(".", $this->_serverdelimiter, $folderid), SA_ALL);
942                if (!$status) {
943                        debugLog("AlterPingChanges: could not stat folder $folderid : ". imap_last_error());
944                        return false;
945                }
946                else {
947                        $newstate = "M:". $status->messages ."-R:". $status->recent ."-U:". $status->unseen;
948
949                        // message number is different - change occured
950                        if ($syncstate != $newstate) {
951                                $syncstate = $newstate;
952                                debugLog("AlterPingChanges: Change FOUND!");
953                                // build a dummy change
954                                return array(array("type" => "fakeChange"));
955                        }
956                }
957
958                return array();
959        }
960
961        // ----------------------------------------
962        // imap-specific internals
963
964        /* Parse the message and return only the plaintext body
965         */
966        function getBody($message, $trunc = false) {
967                $body = "";
968                $htmlbody = "";
969
970                $this->getBodyRecursive($message, "plain", $body);
971                if($trunc == true and isset($body) and strlen($body) > 102400) {
972                        $body = substr($body, 0, 102400);
973                        $body .= "\n\n\n A MENSAGEM FOI TRUNCADA NO CELULAR(MENSAGEM MUITO GRANDE).";
974                }
975
976                if(!isset($body) or $body === '') {
977                        $this->getBodyRecursive($message, "html", $body);
978
979                        if($trunc == true and isset($body) and strlen($body) > 209715) {
980                                $body = substr($body, 0, 209715);
981                                $body .= "<BR><BR><BR> A MENSAGEM FOI TRUNCADA NO CELULAR(MENSAGEM MUITO GRANDE).";
982                    }
983                       
984                        // remove css-style tags
985                        $body = preg_replace("/<style.*?<\/style>/is", "a", $body);
986                        // remove all other html
987                        //$body = strip_tags($body);
988
989                        // Remove the HTML tags using the 'html2text' - emerson-faria.nobre@serpro.gov.br
990                        // The 'html2text' (http://www.mbayer.de/html2text) must be installed in Z-Push server.
991                               
992                        // Advanced debug
993                        // debugLog("IMAP-getBody: subject: " . $message->headers["subject"]);
994                        $body = utf8_encode($body);     
995                        libxml_use_internal_errors(true);
996                        try {
997                                $doc = new DOMDocument('1.0', 'UTF-8');
998                                @$doc->loadHTML($body);
999                                $tables = $doc->getElementsByTagName('table');
1000                                foreach ($tables as $table)
1001                                {
1002                                        $tds = $table->getElementsByTagName('td');
1003                                        foreach ($tds as $td)
1004                                        {
1005                                                foreach ($td->childNodes as $td_child) {
1006                                                        if ($td_child->nodeName == 'br') $td->removeChild($td_child);
1007                                                }
1008                                        }
1009                                }
1010                                $links = $doc->getElementsByTagName('a');
1011                                foreach ($links as $link)
1012                                {
1013                                        if ($link->hasAttributes()){
1014                                                $novoNo = $doc->createTextNode(' (' . $link->getAttribute('href') . ')');
1015                                                $link->parentNode->insertBefore($novoNo, $link->nextSibling);
1016                                        }
1017                                }
1018                                $body =  $doc->saveHTML();
1019                        } catch (Exception $e) {
1020                                debugLog("IMAP-getBody: Alert - DOMDocument cannot parse HTML.");
1021                        }
1022                        $filename = "./state/" . $this->_user . "-" . $this->_devid . ".html";
1023                        $fp = fopen($filename, 'w') or die("can't open file");
1024                        fwrite($fp, $body);
1025                        $body_aux = shell_exec('html2text -nobs -style compact "' . $filename . '"');
1026                        if (trim($body_aux) != '') $body = $body_aux;
1027                        unset($body_aux);
1028                        fclose($fp);
1029                        unlink($filename);
1030                        $body = utf8_decode($body);
1031                        $body = str_replace('_','',$body);
1032                        // End change block - Remove the HTML tags using the 'html2text' Linux application
1033                }
1034
1035                return $body;
1036        }
1037
1038        // Get all parts in the message with specified type and concatenate them together, unless the
1039        // Content-Disposition is 'attachment', in which case the text is apparently an attachment
1040        function getBodyRecursive($message, $subtype, &$body) {
1041                if(!isset($message->ctype_primary)) return;
1042                if(strcasecmp($message->ctype_primary,"text")==0 && strcasecmp($message->ctype_secondary,$subtype)==0 && isset($message->body))
1043                $body .= $message->body;
1044
1045                if(strcasecmp($message->ctype_primary,"multipart")==0 && isset($message->parts) && is_array($message->parts)) {
1046                        foreach($message->parts as $part) {
1047                                if(!isset($part->disposition) || strcasecmp($part->disposition,"attachment"))  {
1048                                        $this->getBodyRecursive($part, $subtype, $body);
1049                                }
1050                        }
1051                }
1052        }
1053
1054        // save the serverdelimiter for later folder (un)parsing
1055        function getServerDelimiter() {
1056                $list = @imap_getmailboxes($this->_mbox, $this->_server, "*");
1057                if (is_array($list)) {
1058                        $val = $list[0];
1059
1060                        return $val->delimiter;
1061                }
1062                return "."; // default "."
1063        }
1064
1065        // speed things up
1066        // remember what folder is currently open and only change if necessary
1067        function imap_reopenFolder($folderid, $force = false) {
1068                // to see changes, the folder has to be reopened!
1069                if ($this->_mboxFolder != $folderid || $force) {
1070                        $s = @imap_reopen($this->_mbox, $this->_server . str_replace(".", $this->_serverdelimiter, $folderid));
1071                        if (!$s) debugLog("failed to change folder: ". implode(", ", imap_errors()));
1072                        $this->_mboxFolder = $folderid;
1073                }
1074        }
1075
1076
1077        // build a multipart email, embedding body and one file (for attachments)
1078        function mail_attach($filenm,$filesize,$file_cont,$body, $body_ct, $body_cte, $boundary = false) {
1079                if (!$boundary) $boundary = strtoupper(md5(uniqid(time())));
1080
1081                //remove the ending boundary because we will add it at the end
1082                $body = str_replace("--$boundary--", "", $body);
1083
1084                $mail_header = "Content-Type: multipart/mixed; boundary=$boundary\n";
1085
1086                // build main body with the sumitted type & encoding from the pda
1087                $mail_body  = $this->enc_multipart($boundary, $body, $body_ct, $body_cte);
1088                $mail_body .= $this->enc_attach_file($boundary, $filenm, $filesize, $file_cont);
1089
1090                $mail_body .= "--$boundary--\n\n";
1091               
1092                return array($mail_header, $mail_body);
1093        }
1094
1095        function enc_multipart($boundary, $body, $body_ct, $body_cte) {
1096//        $mail_body = "This is a multi-part message in MIME format\n\n";   
1097//        $mail_body .= "--$boundary\n";
1098//        $mail_body .= "Content-Type: $body_ct\n";
1099//        $mail_body .= "Content-Transfer-Encoding: $body_cte\n\n";
1100        $mail_body = "$body\n\n";
1101
1102        return $mail_body;
1103        }
1104   
1105        function enc_attach_file($boundary, $filenm, $filesize, $file_cont, $content_type = "") {
1106                if (!$content_type) $content_type = "text/plain";
1107                $mail_body = "--$boundary\n";
1108                $mail_body .= "Content-Type: $content_type; name=\"$filenm\"\n";
1109                $mail_body .= "Content-Transfer-Encoding: base64\n";
1110                $mail_body .= "Content-Disposition: attachment; filename=\"$filenm\"\n";
1111                $mail_body .= "Content-Description: $filenm\n\n";
1112                //contrib - chunk base64 encoded attachments
1113                $mail_body .= chunk_split(base64_encode($file_cont)) . "\n\n";
1114
1115                return $mail_body;
1116        }
1117
1118        // adds a message as seen to a specified folder (used for saving sent mails)
1119        function addSentMessage($folderid, $header, $body) {
1120                $header_body = str_replace("\n", "\r\n", str_replace("\r", "", $header . "\n\n" . $body));
1121
1122                return @imap_append($this->_mbox, $this->_server . $folderid, $header_body, "\\Seen");
1123        }
1124
1125
1126        // parses address objects back to a simple "," separated string
1127        function parseAddr($ad) {
1128                $addr_string = "";
1129                if (isset($ad) && is_array($ad)) {
1130                        foreach($ad as $addr) {
1131                                if ($addr_string) $addr_string .= ",";
1132                                $addr_string .= $addr->mailbox . "@" . $addr->host;
1133                        }
1134                }
1135                return $addr_string;
1136        }
1137
1138};
1139
1140?>
Note: See TracBrowser for help on using the repository browser.