source: trunk/prototype/services/ImapServiceAdapter.php @ 5697

Revision 5697, 20.7 KB checked in by adriano, 12 years ago (diff)

Ticket #2486 - implementa a pasta 'para acompanhamento' e corrige o salvamento

Line 
1<?php
2
3include_once ROOTPATH."/../expressoMail1_2/inc/class.imap_functions.inc.php";
4require_once ROOTPATH.'/library/uuid/class.uuid.php';
5
6
7class ImapServiceAdapter extends imap_functions/* implements Service*/
8{
9    public function open( $config )
10    {
11                $this->init();
12    }
13
14//     public function connect( $config )
15//     {
16//                      $this->init();
17//     }
18       
19    public function find( $URI, $justthese = false, $criteria = false )
20        {
21                $context = $justthese['context'];
22                $URI = $URI['concept'];
23
24                switch( $URI )
25                {
26                        case 'folder':
27                        {
28                                $result = $this->to_utf8($this->get_folders_list());
29
30                                foreach ($result as $res) {
31
32                                        $response[] = array(
33                                                        'id' => $res['folder_id'],
34                                                        'commonName' => $res['folder_name'],
35                                                        'parentFolder' => $res['folder_parent'],
36                                                        'messageCount' => array('unseen' => isset($res['folder_unseen']) ? $res['folder_unseen'] : null, 'total' => null)
37                                                );
38                                }
39
40                                return $response;
41                        }
42                        case 'message':
43                        {
44                                //begin: for grid       
45                                $page  = $criteria['page']; //{1}    get the requested page
46                                $limit = $criteria['rows']; //{10}   get how many rows we want to have into the grid
47                                $sidx  = $criteria['sidx']; //{id}   get index row - i.e. user click to sort
48                                $sord  = $criteria['sord']; //{desc} get the direction
49
50                                $filter = $criteria['filter'];
51
52                                if( !$sidx ) $sidx = 1;
53
54                                $folder_name = str_replace( '.', $this->imap_delimiter, $context['folder'] );
55                               
56                                $count = imap_num_msg( $this->open_mbox( $folder_name ) );
57
58                                $total_pages = $count > 0 ? ceil( $count/$limit ) : 0;
59
60                                if( $page > $total_pages )
61                                        $page = $total_pages;
62
63                                $start = $limit * $page - $limit;
64
65                                // do not put $limit*($page - 1)
66                                //end: for grid
67
68                                if( $filter )
69                                {
70                                        if( $filter[0] !== 'msgNumber' )
71                                        {
72                                        for( $i = 0; $i < count($filter); $i++ )
73                                        {
74                                                if( count( $filter[$i] ) === 4 )
75                                                $criteria['isExact'] = ( array_shift( $filter[$i] ) === 'AND' );
76
77                                                $criteria[ $filter[$i][0] ] = array( 'criteria' => $filter[$i][2], 'filter' => $filter[$i][1] );
78                                        }
79
80                                        return $this->searchSieveRule($criteria);
81                                        }
82
83                                        $msgNumber = array();
84
85                                        for( $i = $start; $i < $start + $limit && isset( $filter[2][$i] ); $i++ )
86                                          $msgNumber[] = $filter[2][$i];
87
88                                        if( empty( $msgNumber ) )
89                                        return( false );
90
91                                        $result = $this->get_info_msgs( array( 'folder' => $folder_name,
92                                                                           'msgs_number' => implode( ',', $msgNumber ) ) );
93
94                                        foreach( $result as $i => $val )
95                                        $result[$i] = unserialize( $val );
96
97                                }
98                                else
99                                {
100                                        $result = $this->get_range_msgs2(
101                                                array(
102                                                        'folder' => $folder_name, //INBOX
103                                                        'msg_range_begin' => $start + 1, //??
104                                                        'msg_range_end' => $start + $limit, //$limit = $_GET['rows']; // get how many rows we want to have into the grid
105                                                        'sort_box_type' => 'SORTARRIVAL',
106                                                        'search_box_type' => 'ALL',
107                                                        'sort_box_reverse' => 1
108                                                )
109                                        );
110                                }
111                                //return var_export($result);
112
113                                $response = array( "page" => $page, "total" => $total_pages, "records" => $count );
114                               
115                                for ($i=0; $i<count($result); $i++)
116                                {
117                                        $flags_enum = array('Recent', 'Unseen',  'Answered',  'Draft',  'Deleted', 'Flagged');
118
119                                        foreach ($flags_enum as $key => $flag)
120                                        {
121                                                if ( !isset($result[$i][$flag]) || !trim($result[$i][$flag]) || trim($result[$i][$flag]) == '')
122                                                        unset($flags_enum[$key]);
123
124                                                unset($result[$i][$flag]);
125                                        }
126
127                                        if (array_key_exists($i, $result))
128                                        {
129                                                $response["rows"][$i] = $result[$i];
130                                                $response["rows"][$i]['timestamp'] = ( ( $result[$i]['udate'] + $this->functions->CalculateDateOffset() ) * 1000 );
131                                                $response["rows"][$i]['flags'] = implode(',', $flags_enum);
132                                                $response["rows"][$i]['size'] = $response["rows"][$i]['Size'];
133                                                //$response["rows"][$i]['udate'] = ( $result[$i]['udate'] + $this->functions->CalculateDateOffset()  * 1000 );
134                                                unset($response["rows"][$i]['Size']);
135                                        }
136                                 }
137
138                                return $this->to_utf8($response);
139                        }
140                       
141                        /**
142                         * Filtros suportados:
143                         * - ['=', 'folderName', $X]
144                         * - [
145                         *              'AND',
146                         *              [
147                         *                      'AND',
148                         *                      ['=', 'folderName', $X],
149                         *                      ['IN', 'messageNumber', $Ys]
150                         *              ],
151                         *              ['IN', 'labelId', $Zs]
152                         * ]
153                         * - ['=', 'labelId', $X]
154                         * - [
155                         *              'AND',
156                         *              ['=', 'folderName', $X],
157                         *              ['=', 'labelId', $Y]
158                         * ]
159                         * - ['IN', 'labelId', $Ys]
160                         * - [
161                         *              'AND',
162                         *              ['=', 'folderName', $X],
163                         *              ['IN', 'labelId', $Ys]
164                         * ]                   
165                         */
166                        case 'labeled':
167                        {
168                                $result = array ( );
169                                if (isset($criteria["filter"]) && is_array($criteria['filter'])) {
170                                        //TODO - melhorar o tratamento do filter com a lista de todos os labelIds dado pelo interceptor
171                                        $map = array(
172                                                'id' => array(),
173                                                'folderName' => array(),
174                                                'messageNumber' => array(),
175                                                'labelId' => array()
176                                        );
177                                       
178                                        self::parseFilter($criteria["filter"], &$map);
179                                       
180                                        if (count($map['folderName']) == 0) {
181                                                $folders = $this->get_folders_list();
182                                                foreach ($folders as $folder)
183                                                        if (isset($folder['folder_id']))
184                                                                $map['folderName'][] = $folder['folder_id'];
185                                        }
186
187                                        foreach ($map['folderName'] as $folder) {
188                                                $this->mbox = $this->open_mbox($folder);
189                                               
190                                                foreach ($map['labelId'] as $label) {
191                                                        $messagesLabeleds = imap_search($this->mbox, 'UNDELETED KEYWORD "$Label'.$label.'"', SE_UID);
192                                                       
193                                                        foreach ($messagesLabeleds as $messageLabeled) {
194                                                                if (count($map['messageNumber']) > 0 && !in_array($messageLabeled, $map['messageNumber']))
195                                                                        continue;
196                                                                       
197                                                                $result[] = array (
198                                                                        'id' => $folder . '/' . $messageLabeled . '#' . $label,
199                                                                        'folderName' => $folder,
200                                                                        'messageNumber' => $messageLabeled,
201                                                                        'labelId' => $label
202                                                                );
203                                                        }
204                                                }
205                                               
206                                                imap_close($this->mbox);
207                                                $this->mbox = false;
208                                        }
209                                }
210                               
211                                return $result;
212                        }
213                       
214                        case 'followupflagged':
215                        {
216                       
217                                $result = array ( );
218                                if (isset($criteria["filter"]) && is_array($criteria['filter'])) {
219                                        //TODO - melhorar o tratamento do filter com a lista de todos os labelIds dado pelo interceptor
220                                        $map = array(
221                                                'id' => array(),
222                                                'folderName' => array(),
223                                                'messageNumber' => array()
224                                        );
225                                       
226                                        self::parseFilter($criteria["filter"], &$map);
227                                       
228                                        if (empty($map['folderName'])) {
229                                                $folders = $this->get_folders_list();
230                                                foreach ($folders as $folder)
231                                                        if (isset($folder['folder_id']))
232                                                                $map['folderName'][] = $folder['folder_id'];
233                                        }
234
235                                        foreach ($map['folderName'] as $folder) {
236                                                $this->mbox = $this->open_mbox($folder);
237                                               
238                                                foreach ($map['id'] as $followupflagged) {
239                                                        $messagesFlaggeds = imap_search($this->mbox, 'UNDELETED KEYWORD "$Followupflag'.$followupflagged.'"', SE_UID);
240                                                       
241                                                        foreach ($messagesFlaggeds as $messageFlagged) {
242                                                                if (count($map['messageNumber']) > 0 && !in_array($messageFlagged, $map['messageNumber']))
243                                                                        continue;
244                                                                       
245                                                                $result[] = array (
246                                                                        'id' => $folder . '/' . $messageFlagged . '#' . $followupflagged,
247                                                                        'folderName' => $folder,
248                                                                        'messageNumber' => $messageFlagged
249                                                                );
250                                                        }
251                                                }
252                                               
253                                                imap_close($this->mbox);
254                                                $this->mbox = false;
255                                        }
256                                }
257                                               
258                                return $result;                         
259                        }
260                }
261    }
262
263    public function read( $URI, $justthese = false )
264    {
265
266                switch( $URI['concept'] )
267                {
268                        case 'message':
269                        {
270                                return $this->to_utf8(
271                                        $this->get_info_msg( array('msg_number'=>$URI['id'],
272                                        'msg_folder'=>str_replace( '.', $this->imap_delimiter, $justthese['context']['folder'] )) )
273                                );
274                        }
275                        case 'labeled':
276                        {
277                                /**
278                                 * id looks like 'folder/subfolder/subsubfolder/65#13', meaning messageId#labelId
279                                 */
280                                list($messageId, $labelId) = explode('#', $URI['id']);
281                                $folderName = basename($messageId);
282                                $messageNumber = dirname($messageId);
283                               
284                                $result = array();
285
286                                if ($folderName && $messageNumber && $labelId) {
287                                        $this->mbox = $this->open_mbox($folderName);
288                                        $messagesLabeleds = imap_search($this->mbox, 'UNDELETED KEYWORD "$Label'.$labelId.'"', SE_UID);
289                                       
290                                        if (in_array($messageNumber, $messagesLabeleds)) {
291                                                $result = array (
292                                                        'id' => $URI['id'],
293                                                        'folderName' => $folderName,
294                                                        'messageNumber' => $messageNumber,
295                                                        'labelId' => $labelId
296                                                );
297                                        }
298                                        imap_close($this->mbox);
299                                        $this->mbox = false;
300                                }
301                               
302                                return $result;
303                        }
304                       
305                        case 'followupflagged':
306                        {
307                                /**
308                                 * id looks like 'folder/subfolder/subsubfolder/65#13', meaning messageId#followupflaggedId
309                                 */
310                                list($messageId, $followupflaggedId) = explode('#', $URI['id']);
311                                $folderName = basename($messageId);
312                                $messageNumber = dirname($messageId);
313                               
314                                $result = array();
315
316                                if ($folderName && $messageNumber && $followupflaggedId) {
317                                        $this->mbox = $this->open_mbox($folderName);
318                                        $messagesFlaggeds = imap_search($this->mbox, 'UNDELETED KEYWORD "$Followupflag'.$followupflaggedId.'"', SE_UID);
319                                       
320                                        if (in_array($messageNumber, $messagesFlaggeds)) {
321                                                $result = array (
322                                                        'id' => $URI['id'],
323                                                        'folderName' => $folderName,
324                                                        'messageNumber' => $messageNumber
325                                                );
326                                        }
327                                        imap_close($this->mbox);
328                                        $this->mbox = false;
329                                }
330                               
331                                return $result;
332                        }
333                }
334    }
335
336    public function create( $URI, $data)
337    {               
338                switch( $URI['concept'] )
339                {
340                        case 'labeled':
341                        {
342                                if (isset($data['folderName']) && isset($data['messageNumber']) && isset($data['labelId'])) {
343                                        $this->mbox = $this->open_mbox($data['folderName']);
344                                        imap_setflag_full($this->mbox, $data['messageNumber'], '$Label' . $data['labelId'], ST_UID);
345
346                                        imap_close($this->mbox);
347                                        $this->mbox = false;
348
349                                        return array ('id' => $data['folderName'].'/'.$data['messageNumber'].'#'.$data['labelId']);
350                                }
351                                return array ();
352                        }
353                        case 'followupflagged':
354                        {
355                                //deve ser gravado no banco primeiro, obtido o id e, depois, gravado no imap passando o id no parametro $data
356                                if (isset($data['folderName']) && isset($data['messageNumber']) && isset($data['id'])) {
357                                        list($messageId, $followupflaggedId) = explode('#', $data['id']);
358                                       
359                                        $this->mbox = $this->open_mbox($data['folderName']);
360                                        imap_setflag_full($this->mbox, $data['messageNumber'], '$Followupflagged $Followupflag' . $followupflaggedId, ST_UID);
361                                       
362                                        /**
363                                         * implementa a possibilidade de listar todas as mensagens sinalizadas através da busca
364                                         */
365                                        //imap_setflag_full($this->mbox, $data['messageNumber'], '$Followupflagged', ST_UID);
366
367                                        imap_close($this->mbox);
368                                        $this->mbox = false;
369
370                                        return array ('id' => $data['id']);
371                                }
372                                return array ();
373                        }
374                       
375                        case 'message':
376                        {
377                                $GLOBALS['phpgw_info']['flags'] = array( 'noheader' => true, 'nonavbar' => true,'currentapp' => 'expressoMail1_2','enable_nextmatchs_class' => True );
378                                $return = array();
379
380                                require_once dirname(__FILE__) . '/../../services/class.servicelocator.php';
381                                $mailService = ServiceLocator::getService('mail');
382
383                                $msg_uid = $data['msg_id'];
384                                $body = $data['body'];
385                                $body = str_replace("%nbsp;","&nbsp;",$body);
386                                $body = preg_replace("/\n/"," ",$body);
387                                $body = preg_replace("/\r/","" ,$body);
388                                $body = html_entity_decode ( $body, ENT_QUOTES , 'ISO-8859-1' );                                       
389
390                                $folder = mb_convert_encoding($data['folder'], "UTF7-IMAP","ISO-8859-1, UTF-8");
391                                $folder = @eregi_replace("INBOX[/.]", "INBOX".$this->imap_delimiter, $folder);
392
393                                                                /**
394                                                                 * Gera e preenche o field Message-Id do header
395                                                                 */
396                                                                $mailService->addHeaderField('Message-Id', UUID::generate( UUID::UUID_RANDOM, UUID::FMT_STRING ) . '@Draft');
397                                                               
398                                $mailService->addTo($data['input_to']);
399                                $mailService->addCc( $data['input_cc']);
400                                $mailService->addBcc($data['input_cco']);
401                                $mailService->setSubject($data['input_subject']);
402                                if(isset($data['input_important_message']))
403                                        $mailService->addHeaderField('Importance','High');
404
405                                if(isset($data['input_return_receipt']))
406                                        $mailService->addHeaderField('Disposition-Notification-To', Config::me('mail'));
407
408                                $isHTML = ( ( array_key_exists( 'type', $data ) && in_array( strtolower( $data[ 'type' ] ), array( 'html', 'plain' ) ) ) ? strtolower( $data[ 'type' ] ) != 'plain' : true );
409
410                                if (!$body) $body = ' ';
411                               
412
413                                $mbox_stream = $this->open_mbox($folder);
414
415                                $attachment = json_decode($data['attachments'],TRUE);
416                               
417
418                                foreach ($attachment as &$value)
419                                {
420
421                                    if((int)$value > 0) //BD attachment
422                                    {
423                                         $att = Controller::read(array('id'=> $value , 'concept' => 'mailAttachment'));
424                                         
425                                         
426                                         if($att['disposition'] == 'embedded')
427                                         {
428                                             $body = str_replace('"../prototype/getArchive.php?mailAttachment='.$att['id'].'"', $att['name'], $body);
429                                             $mailService->addStringImage(base64_decode($att['source']), $att['type'], $att['name']);
430                                         }
431                                         else
432                                             $mailService->addStringAttachment(base64_decode($att['source']), $att['name'], $att['type'], 'base64', isset($att['disposition']) ? $att['disposition'] :'attachment' );
433                                         
434                                         unset($att);
435                                    }
436                                    else
437                                    {
438                                        $value = json_decode($value, true);
439                                       
440                                        switch ($value['type']) {
441                                            case 'imapPart':
442                                                    $att = $this->getForwardingAttachment($value['folder'],$value['uid'], $value['part']);
443                                                    if(strstr($body,'<img src="./inc/get_archive.php?msgFolder='.$value['folder'].'&msgNumber='.$value['uid'].'&indexPart='.$value['part'].'" />') !== false)//Embeded IMG
444                                                    {   
445                                                        $body = str_ireplace('<img src="./inc/get_archive.php?msgFolder='.$value['folder'].'&msgNumber='.$value['uid'].'&indexPart='.$value['part'].'" />' , '<img src="'.$att['name'].'" />', $body);
446                                                        $mailService->addStringImage($att['source'], $att['type'], $att['name']);
447                                                    }
448                                                    else
449                                                        $mailService->addStringAttachment($att['source'], $att['name'], $att['type'], 'base64', isset($att['disposition']) ? $att['disposition'] :'attachment' );
450                                                    unset($att);
451                                                break;
452                                              case 'imapMSG':
453                                                    $sub =  $value['name'] ? $value['name'].'.eml' :'no title.eml';
454                                                    $mbox_stream = $this->open_mbox($value['folder']);
455                                                    $rawmsg = $this->getRawHeader($value['uid']) . "\r\n\r\n" . $this->getRawBody($value['uid']);
456                                                    $mailService->addStringAttachment($rawmsg, $sub, 'message/rfc822', '7bit', 'attachment' );
457                                                    unset($rawmsg);
458                                                break;
459
460                                            default:
461                                                break;
462                                        }
463                                    }
464
465                                }
466                               
467                                if($isHTML) $mailService->setBodyHtml($body); else $mailService->setBodyText($body);
468 
469                                if(imap_append($mbox_stream, "{".$this->imap_server.":".$this->imap_port."}".$folder, $mailService->getMessage(), "\\Seen \\Draft"))
470                                {
471                                    $status = imap_status($mbox_stream, "{".$this->imap_server.":".$this->imap_port."}".$folder, SA_UIDNEXT);
472                                    $return['id'] = $status->uidnext - 1;
473                                       
474                                    if($data['uidsSave'] )
475                                        $this->delete_msgs(array('folder'=> $folder , 'msgs_number' => $data['uidsSave']));
476                       
477                                }
478                 
479                                if($mbox_stream) imap_close($mbox_stream);
480
481                                return $return;
482                        }
483                }
484        }
485
486    public function delete( $URI, $justthese = false, $criteria = false )
487    {
488                switch( $URI['concept'] )
489                {
490                        case 'labeled':
491                        {
492                                list($messageId, $labelId) = explode('#', $URI['id']);
493                                $folderName = dirname($messageId);
494                                $messageNumber = basename($messageId);
495
496                                if ($folderName && $messageNumber && $labelId) {
497                                        $this->mbox = $this->open_mbox($folderName);
498                                        imap_clearflag_full($this->mbox, $messageNumber, '$Label' . $labelId, ST_UID);
499
500                                        imap_close($this->mbox);
501                                        $this->mbox = false;
502                                }
503                        }
504                        case 'followupflagged':
505                        {
506                                list($messageId, $followupflaggedId) = explode('#', $URI['id']);
507                               
508                                $folderName = dirname($messageId);
509                                $messageNumber = basename($messageId);
510                       
511                                if ($folderName && $messageNumber && $followupflaggedId) {
512
513                                        $this->mbox = $this->open_mbox($folderName);
514                                        imap_clearflag_full($this->mbox, $messageNumber, '$Followupflag' . $followupflaggedId, ST_UID);
515
516                                        /**
517                                         * implementa a possibilidade de listar todas as mensagens sinalizadas através da busca
518                                         */
519                                        imap_clearflag_full($this->mbox, $messageNumber, '$Followupflagged', ST_UID);
520
521                                        imap_close($this->mbox, CL_EXPUNGE);
522                                        $this->mbox = false;
523                                }
524                        }
525                }
526
527                //TODO - return
528        }
529
530    public function deleteAll( $URI, $justthese = false, $criteria = false ) // avaliar
531    {}
532
533    public function update( $URI, $data, $criteria = false )
534    {
535                /**
536                 * Os únicos atributos que podem ser alterados no IMAP são folderName e messageId,
537                 * porém a operação de update desses atributos não faz sentido para o usuário da DataLayer,
538                 * pois na prática elas são executadas através das operações de CREATE e DELETE.
539                 * Assim, para os conceitos "labeled" e "followupflagged", só faz sentido o update de
540                 * atributos gravados no banco de dados e nunca no IMAP.
541                 */
542        }
543
544//     public function retrieve( $concept, $id, $parents, $justthese = false, $criteria = false )
545//     {
546//                      return $this->read( array( 'id' => $id,
547//                          'concept' => $concept,
548//                          'context' => $parents ), $justthese );
549//     }
550
551    public function replace( $URI, $data, $criteria = false )
552    {}
553
554    public function close()
555    {}
556
557    public function setup()
558    {}
559
560    public function commit( $uri )
561    { return( true ); }
562
563    public function rollback( $uri )
564    {}
565
566    public function begin( $uri )
567    {}
568
569
570    public function teardown()
571    {}
572
573    function to_utf8($in)
574    {
575                if (is_array($in)) {
576                        foreach ($in as $key => $value) {
577                                $out[$this->to_utf8($key)] = $this->to_utf8($value);
578                        }
579                } elseif(is_string($in)) {
580                                return mb_convert_encoding( $in , 'UTF-8' , 'UTF-8 , ISO-8859-1' );
581                } else {
582                        return $in;
583                }
584                return $out;
585    }
586       
587           
588    private static function parseFilter($filter ,&$map){
589               
590                if( !is_array( $filter ) || count($filter) <= 0) return null;
591                                       
592                $op = array_shift( $filter );
593                switch(strtolower($op))
594                {
595                        case 'and': {
596                                foreach ($filter as $term)
597                                        self::parseFilter($term ,&$map);
598                                return;
599                        }
600                        case 'in': {
601                                if(is_array($map[$filter[0]]) && is_array($filter[1]))
602                                        $map[$filter[0]] = array_unique(array_merge($map[$filter[0]], $filter[1]));
603                                return;
604                        }
605                        case '=': {
606                                $map[$filter[0]][] = $filter[1];
607                        }
608                }
609        }
610
611}
Note: See TracBrowser for help on using the repository browser.