tizen beta release
[framework/messaging/email-service.git] / email-core / em-core-imap-idle.c
1 /*
2 *  email-service
3 *
4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5 *
6 * Contact: Kyuho Jo <kyuho.jo@samsung.com>, Sunghyun Kwon <sh0701.kwon@samsung.com>
7
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 *
20 */
21
22 /**
23  *
24  * This file contains functinality related to IMAP IDLE.
25  * to interact with Email Engine.
26  * @file                em_core-imap-idle.c
27  * @author      
28  * @version     0.1
29  * @brief               This file contains functionality to provide IMAP IDLE support in email-service. 
30  */
31
32 #include <em-core-types.h>
33
34 #ifdef _FEATURE_IMAP_IDLE
35 #include <pthread.h>
36 #include <glib.h>
37 #include <openssl/ssl.h>
38 #include "c-client.h"
39 #include "lnx_inc.h"
40 #include "em-core-imap-idle.h"
41 #include "emf-dbglog.h"
42 #include "em-storage.h" 
43 #include "em-network.h"
44 #include "em-core-utils.h"
45 #include "em-core-mailbox.h"
46 #include "em-core-event.h"
47 #include "em-core-account.h"
48
49 static int idle_pipe[2] = {0, 0};
50
51 static int wait_on_pipe(int *pipe_fd)
52 {
53         fd_set rfds;
54         fd_set wfds;
55         struct timeval timeout_value;
56         int    ret_value;
57         
58         FD_ZERO(&rfds);
59         FD_ZERO(&wfds);
60         FD_SET(pipe_fd[0], &rfds);
61         
62         EM_DEBUG_LOG("wait...till dnet fills some data in pipe - %d", pipe_fd[0]);
63
64         /* timeout_value.tv_sec = 10; */ /*  10 seconds. */
65         timeout_value.tv_sec = 180; /*  160 + a seconds. */
66         timeout_value.tv_usec = 0; 
67         EM_DEBUG_LOG("wait_on_pipe()  :  timeout_value (%d) sec, (%d) usec", timeout_value.tv_sec, timeout_value.tv_usec);
68         
69         ret_value = select(pipe_fd[0]+1, &rfds, &wfds, NULL, &timeout_value);
70
71         switch (ret_value){
72                 case 0:
73                         EM_DEBUG_LOG("wait_on_pipe()  :  select timer expired!!! ");
74                         break;
75                 case -1:
76                         EM_DEBUG_LOG("wait_on_pipe()  :  There is an error on calling select. ");
77                         break;
78                 default:
79                         EM_DEBUG_LOG("wait_on_pipe()  :  got response from DNET. ");
80                         break;
81         }
82         
83         return ret_value;
84 }
85
86 static int read_from_pipe(int *pipe_fd)
87 {
88         int activation = 0;
89         
90         read(pipe_fd[0], &activation, sizeof(int));
91         
92         return activation;
93 }
94
95 static void write_to_pipe(int *pipe_fd, int result)
96 {
97         write(pipe_fd[1], (char *)&result, sizeof(int)); 
98 }
99
100
101 static void _idle_thread_cm_evt_cb(const NetEventInfo_t *event)
102 {
103         EM_DEBUG_FUNC_BEGIN();
104         
105         /* This callback will be called when any event is recd from datacom */
106         
107         switch (event->Event) {
108                 /* Response from Datacom for PDP Activation Request */
109                 case NET_EVENT_OPEN_RSP: 
110                         if (event->Error == NET_ERR_NONE) {             /* Successful PDP Activation */
111                                 EM_DEBUG_LOG("\t IMAP IDLE Successful PDP Activation");
112                                 
113                                 NetDevInfo_t devInfo;
114                                 memset(&devInfo, 0x00, sizeof(devInfo));
115                                 
116                                 if (net_get_device_info(&devInfo) != NET_ERR_NONE) 
117                                         EM_DEBUG_EXCEPTION("\t net_get_device_info failed - %d", event->Error);
118                                 write_to_pipe(idle_pipe, 1);
119                         }
120                         else {          /* PDP Activation failure */
121                                 EM_DEBUG_EXCEPTION("\t PDP Activation Failure %d", event->Error);
122                                 write_to_pipe(idle_pipe, 0);
123                         }
124                         break;
125                 
126                 /* Response from Datacom for PDP Dectivation Request */
127                 case NET_EVENT_CLOSE_RSP: 
128                         if (event->Error == NET_ERR_NONE) {             /* Successful PDP Dectivation */
129                                 EM_DEBUG_LOG("\t Successful PDP DeActivation");
130                                 
131                                 write_to_pipe(idle_pipe, 1);
132                         }
133                         else {          /* PDP Dectivation failure */
134                                 EM_DEBUG_EXCEPTION("\t PDP DeActivation Failure %d", event->Error);
135                                 
136                                 if (event->Error == NET_ERR_TRANSPORT) 
137                                 {
138                                         /*  TODO  :  add a process to deal an error */
139                                         /* NetCMGetTransportError(&err_code); */
140                                 }
141                                 
142                                 write_to_pipe(idle_pipe, 0);
143                         }
144                         break;
145                 
146                 case NET_EVENT_CLOSE_IND: 
147                         EM_DEBUG_LOG("NET_EVENT_CLOSE_IND recieved");
148                         break;
149                 
150                 case NET_EVENT_KILL_RSP: 
151                         break;
152                 
153                 case NET_EVENT_SUSPEND_IND: 
154                         /*  TODO */
155                         /*  think over what can we do... */
156                         break;
157                 
158                 case NET_EVENT_RESUME_IND: 
159                         /*  TODO */
160                         /*  think over what can we do... */
161                         break;
162                 
163                 default: 
164                         break;
165         }
166 }
167
168
169 /*Definitions copied temperorily from ssl_unix.c */
170 #define SSLBUFLEN 8192
171
172 typedef struct ssl_stream {
173   TCPSTREAM *tcpstream;         /* TCP stream */
174   SSL_CTX *context;             /* SSL context */
175   SSL *con;                     /* SSL connection */
176   int ictr;                     /* input counter */
177   char *iptr;                   /* input pointer */
178   char ibuf[SSLBUFLEN];         /* input buffer */
179 } SSLSTREAM;
180 /*Definitions copied temperorily from ssl_unix.c - end*/
181
182 thread_t imap_idle_thread = NULL;
183 int g_imap_idle_thread_alive = 0;
184
185
186 int em_core_imap_idle_thread_create(int accountID, int *err_code)
187 {
188         EM_DEBUG_FUNC_BEGIN();
189         int ret = false;
190         int thread_error = -1;
191
192 #ifdef ENABLE_IMAP_IDLE_THREAD          
193
194         g_imap_idle_thread_alive = 1;   
195         THREAD_CREATE(imap_idle_thread, em_core_imap_idle_run, NULL, thread_error);
196         if (thread_error != 0)
197         {
198                 EM_DEBUG_EXCEPTION("cannot make IMAP IDLE thread...");
199                 if (err_code != NULL) 
200                         *err_code = EMF_ERROR_UNKNOWN;
201                 g_imap_idle_thread_alive = 0;   
202                 goto FINISH_OFF;
203         }
204         
205         ret = true;
206 FINISH_OFF: 
207
208 #else /*  ENABLE_IMAP_IDLE_THREAD */
209         EM_DEBUG_LOG(">>>>>>>> DISABLED IMAP IDLE THREAD");
210 #endif /*  ENABLE_IMAP_IDLE_THREAD */
211
212         return ret;
213 }
214
215 /*
216 Need to identify various scenarios where thread needs to be killed
217 1. After the timer set to 10 min expires.
218 2. When No sim, thread is created and em_core_check_network_status() fails. 
219 */
220 int em_core_imap_idle_thread_kill(int *err_code)
221 {
222         EM_DEBUG_FUNC_BEGIN();
223         int ret = true;
224         int err = EMF_ERROR_NONE;
225         
226         EM_DEBUG_LOG(">>>>>>>>>>>>killing thread>>>>>>>>>");
227         
228         /* kill the thread */
229         EM_DEBUG_LOG(">>>>>>>>>Before g_thread_exit");
230         g_imap_idle_thread_alive = 0;
231         EM_DEBUG_LOG(">>>>>>>>>After g_thread_exit");
232
233         EM_DEBUG_LOG(">>>>>>>>>>>>>>>>>> Making imap idle NULL>>>>>>>>>>>>>>>>>");
234         imap_idle_thread = NULL;
235         EM_DEBUG_LOG(">>>>>>>>>>>>>>>>>> killed IMAP IDLE >>>>>>>>>>>>>>>>>");
236         if (err_code)
237                 *err_code = err;
238         return ret;
239 }
240
241
242
243 int em_core_imap_idle_run(int accountID)
244 {
245         EM_DEBUG_FUNC_BEGIN();
246         char *mailbox_list[3]; /* Temperory - To be modified to char ***/
247         int mailbox_num = 0;
248         emf_mailbox_t *mail_box_list = NULL;
249         emf_mailbox_t *curr_mailbox = NULL;
250         emf_mailbox_t *prev_mailbox = NULL;
251         int counter = 0;
252         emf_mailbox_tbl_t *local_mailbox = NULL;
253         int err = EMF_ERROR_NONE;
254         int flag = true; 
255         int num = 0;
256         emf_session_t *session = NULL;
257         int ret = false;
258
259         if ( !em_core_check_network_status(&err)) {
260                 EM_DEBUG_EXCEPTION("em_core_check_network_status failed [%d]", err);
261                 return ret;
262         }
263         /* Connect to DB */
264         if (!em_storage_open(&err)) {
265                 EM_DEBUG_EXCEPTION("\t em_storage_open falied - %d", err);
266                 goto FINISH_OFF;
267         }
268
269         if (!em_core_get_empty_session(&session))  
270                         EM_DEBUG_EXCEPTION("\t em_core_get_empty_session failed...");
271         
272         /* get the list of mailbox name on which IDLE notifications are required. */
273         /* currently all INBOXES of all accounts need to be notified */
274         /* Dependent on GetMyIdentities for account names */
275
276         /* For testing - mailbox_num and mailbox_list are hardcoded here */
277         mailbox_num = 1;
278         mailbox_list[0] = EM_SAFE_STRDUP("INBOX");
279
280         /* make a list of mailboxes IDLING */
281         for (counter = 0; counter < mailbox_num; counter++){
282                 EM_DEBUG_EXCEPTION(">>>> em_core_imap_idle_run 4 ");
283                 if (!em_storage_get_mailbox_by_name(accountID, 0,  mailbox_list[counter], &local_mailbox, true, &err)) {
284                         EM_DEBUG_EXCEPTION("em_storage_get_mailbox_by_name failed - %d", err);
285                 }
286
287                 else {
288                         curr_mailbox = em_core_malloc(sizeof(emf_mailbox_t));
289
290                         curr_mailbox->account_id = local_mailbox->account_id;
291                         curr_mailbox->name = EM_SAFE_STRDUP(local_mailbox->mailbox_name);
292                         curr_mailbox->local = local_mailbox->local_yn;
293                         if (!em_core_imap_idle_connect_and_idle_on_mailbox(curr_mailbox, &err)) {
294                                 EM_DEBUG_EXCEPTION("em_core_imap_idle_connect_and_idle_on_mailbox failed - %d", err);
295                                 em_core_mailbox_free(&curr_mailbox, 1, NULL);
296                         }
297                         else {
298                                 if (flag) {
299                                         mail_box_list = curr_mailbox;
300                                         prev_mailbox = curr_mailbox;
301                                         flag = false;
302                                         num++;
303                                 }
304
305                                 else {
306                                         prev_mailbox->next = curr_mailbox;
307                                         prev_mailbox = curr_mailbox;
308                                         num++;
309                                 }
310                                 
311                         }
312                         
313                 }
314                 if (local_mailbox != NULL)
315                         em_storage_free_mailbox(&local_mailbox, 1, NULL);
316
317         }
318
319         em_core_clear_session(session);
320
321         em_core_imap_idle_loop_start(mail_box_list, num, NULL);
322
323         EM_DEBUG_EXCEPTION("IMAP IDLE ");
324
325         ret = true;
326 FINISH_OFF: 
327         if (!em_storage_close(&err)) {
328                 EM_DEBUG_EXCEPTION("\t em_storage_close falied - %d", err);
329         }
330
331         return ret;
332         
333 }
334
335 int em_core_imap_idle_loop_start(emf_mailbox_t *mailbox_list,  int num, int *err_code)
336 {
337         EM_DEBUG_FUNC_BEGIN();
338         fd_set readfds;
339         int maxfd = 0;
340         int err = EMF_ERROR_NONE;
341         int counter = 0;
342         int select_result = 0;
343         int ret = false;
344         emf_mailbox_t *temp = NULL;
345         struct timeval timeout;
346
347         EM_DEBUG_EXCEPTION(">>>>>>> em_core_imap_idle_loop_start start ");
348         if (!mailbox_list || !num) {
349                 EM_DEBUG_EXCEPTION("\t mailbox_list[%p], num[%d]", mailbox_list, num);
350                 
351                 err = EMF_ERROR_INVALID_PARAM;
352                 goto FINISH_OFF;
353         }
354
355         /* set timeout value to 10min */
356         timeout.tv_sec = 10 * 60;
357         timeout.tv_usec = 0;
358
359         /* IMAP IDLE LOOP */
360         while (1){
361                 EM_DEBUG_EXCEPTION(">>>>>>>>>>>IDLING>>>>>>>>>>>>");
362                 FD_ZERO(&readfds);
363                 temp = mailbox_list;
364                 for (counter = 0; counter < num; counter++) {
365                         FD_SET(temp->hold_connection, &readfds);
366                         if (temp->hold_connection > maxfd)
367                                 maxfd = temp->hold_connection; 
368                         temp = temp->next;
369                 }
370                 maxfd++;
371                 temp = mailbox_list;
372                 
373                 select_result = select(maxfd, &readfds, NULL, NULL, &timeout);
374
375                 if (select_result > 0) /* Data coming on some socket */ {
376                         EM_DEBUG_EXCEPTION(">>>> Data Coming from Socket ");
377                         for (counter = 0; counter < num; counter++) {
378                                 if (temp && FD_ISSET(temp->hold_connection, &readfds)) {
379                                         if (!em_core_imap_idle_parse_response_stream(temp, &err)) {
380                                                 EM_DEBUG_EXCEPTION(">>>> em_core_imap_idle_loop_start 6 ");
381                                                 em_core_mailbox_close(temp->account_id, temp->mail_stream);
382                                                 EM_DEBUG_EXCEPTION(">>>> em_core_imap_idle_loop_start 7 ");
383                                                 goto FINISH_OFF;
384                                         }
385                                         break; /* break for now - check if it is possible to get data on two sockets - shasikala.p */
386                                 }
387                                 temp = temp->next;
388                         }
389                 }
390
391                 else if (select_result == 0) /* Timeout occured */ {
392                         EM_DEBUG_EXCEPTION(">>>> em_core_imap_idle_loop_start 8 ");
393                         IMAPLOCAL *imap_local = NULL;
394                         char cmd[128], tag[32];
395                         char *p = NULL;
396                         /* send DONE Command */
397                         /* free all data here */
398                         for (counter = 0; counter < num; counter++) {
399                                 EM_DEBUG_LOG(">>>> em_core_imap_idle_loop_start 9 ");
400                                 if (temp && temp->mail_stream) {
401                                         imap_local = ((MAILSTREAM *)temp->mail_stream)->local;
402
403                                         sprintf(tag, "%08lx", 0xffffffff & (((MAILSTREAM *)temp->mail_stream)->gensym++));
404                                         sprintf(cmd, "%s DONE\015\012", tag);
405
406                                         if (!imap_local->netstream || !net_sout(imap_local->netstream, cmd, (int)strlen(cmd)))
407                                         {
408                                                 EM_DEBUG_EXCEPTION("network error - failed to DONE on Mailbox - %s ", temp->name);
409                                         }
410                                         else {
411                                                 while (imap_local->netstream) {
412                                                 p = net_getline(imap_local->netstream);
413                                                 EM_DEBUG_EXCEPTION("p =[%s]", p);
414                                                         em_core_mailbox_close(temp->account_id, temp->mail_stream);
415                                                         break;
416                                                 }
417                                         }
418                                 }
419                 
420                                 temp = temp->next;
421                         }
422                         
423                         
424                         /* kill idle thread */
425                         em_core_imap_idle_thread_kill(&err);
426                         break;
427                 }
428
429                 else {
430                         /*
431                         might happen that a socket desciptor passed to select got closed
432                         chack which got closed and make hold_connection 0
433                         */
434                         EM_DEBUG_EXCEPTION(">>>>>> socket desciptor error :  No Data ");
435                         break;
436                 }
437
438                 select_result = 0;
439         }
440
441         ret = true;
442
443         EM_DEBUG_LOG(">>>> em_core_imap_idle_loop_start 17  ");
444 FINISH_OFF: 
445         if (err_code)
446                 *err_code = err;
447         EM_DEBUG_EXCEPTION(">>>>>>> em_core_imap_idle_loop_start End ");
448         return ret;
449 }
450
451
452 int em_core_imap_idle_insert_sync_event(emf_mailbox_t *mailbox, int *err_code)
453 {
454         EM_DEBUG_FUNC_BEGIN();
455         
456         int ret = false;
457         int err = EMF_ERROR_NONE;
458         int handle;
459         
460         if (!mailbox || mailbox->account_id <= 0) {
461                 EM_DEBUG_LOG("\t mailbox[%p]", mailbox);
462                 
463                 err = EMF_ERROR_INVALID_PARAM;
464                 goto FINISH_OFF;
465         }
466         emf_event_t event_data;
467         memset(&event_data, 0x00, sizeof(emf_event_t));
468
469         event_data.type = EMF_EVENT_SYNC_HEADER;
470         event_data.event_param_data_1 = mailbox ? EM_SAFE_STRDUP(mailbox->name)  :  NULL;
471         event_data.event_param_data_3 = NULL;
472         event_data.account_id = mailbox->account_id;
473                         
474         if (!em_core_insert_event(&event_data, &handle, &err)) {
475                 EM_DEBUG_LOG("\t em_core_insert_event falied - %d", err);
476                                 
477                 /* err = EMF_ERROR_DB_FAILURE; */
478                 goto FINISH_OFF;
479         }
480
481         ret = true;
482 FINISH_OFF: 
483         if (err_code)
484                 *err_code = err;
485         
486         return ret;
487 }
488
489 /* connects to given mailbox. send idle and returns socket id */
490 int em_core_imap_idle_connect_and_idle_on_mailbox(emf_mailbox_t *mailbox, int *err_code)
491 {
492         EM_DEBUG_FUNC_BEGIN();  
493         void *mail_stream = NULL;
494         char cmd[128], tag[32], *p;
495         int socket_id = 0;
496         int ret = 0;
497         int err = EMF_ERROR_NONE;
498         emf_account_t *ref_account = NULL;
499
500         /* NULL param check */
501         if (!mailbox) {
502                 EM_DEBUG_EXCEPTION("\t mailbox[%p]", mailbox);
503                 if (err_code)
504                         *err_code = EMF_ERROR_INVALID_PARAM;
505                 goto FINISH_OFF;
506         }
507
508         ref_account = em_core_get_account_reference(mailbox->account_id);
509         if (!ref_account) {
510                 EM_DEBUG_EXCEPTION("\t em_core_get_account_reference failed - %d", mailbox->account_id);
511                 
512                 err = EMF_ERROR_INVALID_ACCOUNT;
513                 goto FINISH_OFF;
514         }
515
516         /* Open connection to mailbox */
517         if (!em_core_mailbox_open(mailbox->account_id, mailbox->name, (void **)&mail_stream, &err) || !mail_stream) {
518                 EM_DEBUG_EXCEPTION("\t em_core_mailbox_open failed - %d", err);
519                 if (err_code)
520                         *err_code = err;
521                 goto FINISH_OFF;
522         }
523
524         IMAPLOCAL *imap_local = ((MAILSTREAM *)mail_stream)->local;
525         NETSTREAM *net_stream = imap_local->netstream;
526         
527         /* check if ssl option is enabled on this account - shasikala.p */
528         TCPSTREAM *tcp_stream = NULL;
529         if (ref_account->use_security){
530         SSLSTREAM *ssl_stream = net_stream->stream;
531                 tcp_stream = ssl_stream->tcpstream;
532         }
533         else{
534                 tcp_stream = net_stream->stream;
535         }
536
537         /* Get Socket ID */
538         socket_id = ((TCPSTREAM *)tcp_stream)->tcpsi;
539
540         sprintf(tag, "%08lx", 0xffffffff & (((MAILSTREAM *)mail_stream)->gensym++));
541         sprintf(cmd, "%s IDLE\015\012", tag);
542
543         /* Send IDLE command */
544         if (!imap_local->netstream || !net_sout(imap_local->netstream, cmd, (int)strlen(cmd)))
545         {
546                 EM_DEBUG_EXCEPTION("network error - failed to IDLE on Mailbox - %s ", mailbox->name);
547                 if (err_code)
548                         *err_code = EMF_ERROR_IMAP4_IDLE_FAILURE;
549                 goto FINISH_OFF;
550         }
551
552         /* Get the response for IDLE command */
553         while (imap_local->netstream){
554                 p = net_getline(imap_local->netstream);
555                 EM_DEBUG_LOG("p =[%s]", p);
556                 if (!strncmp(p, "+", 1)) {
557                         ret = 1;
558                         break;
559                 }
560                 else if (!strncmp(p, "*", 1)) {
561                             EM_SAFE_FREE(p);
562                             continue;
563                 }
564                 else {
565                         ret = 0;
566                         break;
567                 }
568     }
569         EM_SAFE_FREE(p); /* Prevent Defect - 18815 */
570
571 FINISH_OFF: 
572         
573         if (ret)                /* IMAP IDLE - SUCCESS */{
574                 mailbox->mail_stream = mail_stream;
575                 mailbox->hold_connection = socket_id; /* holds connection continuosly on the given socket_id */
576         }
577         else
578                 if (mail_stream) em_core_mailbox_close(mailbox->account_id, mail_stream);
579         return ret;
580 }
581
582
583 int em_core_imap_idle_parse_response_stream(emf_mailbox_t *mailbox, int *err_code)
584 {
585         EM_DEBUG_FUNC_BEGIN();
586         int err = EMF_ERROR_NONE;
587         char *p = NULL;
588         int ret = false;
589         
590         /* NULL PARAM CHECK */
591         if (!mailbox) {
592                 EM_DEBUG_EXCEPTION("\t mailbox[%p]", mailbox);
593                 if (err_code)
594                         *err_code = EMF_ERROR_INVALID_PARAM;
595                 goto FINISH_OFF;
596         }
597         
598         IMAPLOCAL *imap_local = NULL;
599
600         if (!mailbox->mail_stream){
601                 EM_DEBUG_EXCEPTION("mail_stream is NULL");
602                 goto FINISH_OFF;
603         }               
604
605         imap_local = ((MAILSTREAM *)mailbox->mail_stream)->local;
606
607         if (!imap_local){
608                 EM_DEBUG_EXCEPTION("imap_local is NULL");
609                 goto FINISH_OFF;
610         }
611
612
613         while (imap_local->netstream){
614                 p = net_getline(imap_local->netstream);
615                 if (p && !strncmp(p, "*", 1)) {
616                         EM_DEBUG_LOG("p is [%s]", p);
617                         if (p+1 && p+2 && p+3 && p+4 && !strncmp(p+2, "BYE", 3)) {
618                                 EM_DEBUG_LOG("BYE connection from server");
619
620                                 EM_SAFE_FREE(p);
621                                 goto FINISH_OFF;
622                         }
623                         else  { 
624                         if (!em_core_imap_idle_insert_sync_event(mailbox, &err))
625                                 EM_DEBUG_EXCEPTION("Syncing mailbox %s failed with err_code - %d", mailbox->name, err);
626                                 EM_SAFE_FREE(p);        
627                         break;
628                 }
629                         
630                         
631                 }
632                 else if (p && (!strncmp(p, "+", 1))) {
633                         /* Bad response from server */
634                         EM_DEBUG_LOG("p is [%s]", p);
635                         EM_SAFE_FREE(p);
636                         break;
637                 }
638                 else {
639                         EM_DEBUG_LOG("In else part");
640                         break;
641                 }
642         }
643
644         ret = true;
645 FINISH_OFF: 
646         return ret;
647 }
648 #endif /*  _FEATURE_IMAP_IDLE */