4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Kyuho Jo <kyuho.jo@samsung.com>, Sunghyun Kwon <sh0701.kwon@samsung.com>
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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.
24 * This file contains functinality related to IMAP IDLE.
25 * to interact with Email Engine.
26 * @file em_core-imap-idle.c
29 * @brief This file contains functionality to provide IMAP IDLE support in email-service.
32 #include <em-core-types.h>
34 #ifdef _FEATURE_IMAP_IDLE
37 #include <openssl/ssl.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"
49 static int idle_pipe[2] = {0, 0};
51 static int wait_on_pipe(int *pipe_fd)
55 struct timeval timeout_value;
60 FD_SET(pipe_fd[0], &rfds);
62 EM_DEBUG_LOG("wait...till dnet fills some data in pipe - %d", pipe_fd[0]);
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);
69 ret_value = select(pipe_fd[0]+1, &rfds, &wfds, NULL, &timeout_value);
73 EM_DEBUG_LOG("wait_on_pipe() : select timer expired!!! ");
76 EM_DEBUG_LOG("wait_on_pipe() : There is an error on calling select. ");
79 EM_DEBUG_LOG("wait_on_pipe() : got response from DNET. ");
86 static int read_from_pipe(int *pipe_fd)
90 read(pipe_fd[0], &activation, sizeof(int));
95 static void write_to_pipe(int *pipe_fd, int result)
97 write(pipe_fd[1], (char *)&result, sizeof(int));
101 static void _idle_thread_cm_evt_cb(const NetEventInfo_t *event)
103 EM_DEBUG_FUNC_BEGIN();
105 /* This callback will be called when any event is recd from datacom */
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");
113 NetDevInfo_t devInfo;
114 memset(&devInfo, 0x00, sizeof(devInfo));
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);
120 else { /* PDP Activation failure */
121 EM_DEBUG_EXCEPTION("\t PDP Activation Failure %d", event->Error);
122 write_to_pipe(idle_pipe, 0);
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");
131 write_to_pipe(idle_pipe, 1);
133 else { /* PDP Dectivation failure */
134 EM_DEBUG_EXCEPTION("\t PDP DeActivation Failure %d", event->Error);
136 if (event->Error == NET_ERR_TRANSPORT)
138 /* TODO : add a process to deal an error */
139 /* NetCMGetTransportError(&err_code); */
142 write_to_pipe(idle_pipe, 0);
146 case NET_EVENT_CLOSE_IND:
147 EM_DEBUG_LOG("NET_EVENT_CLOSE_IND recieved");
150 case NET_EVENT_KILL_RSP:
153 case NET_EVENT_SUSPEND_IND:
155 /* think over what can we do... */
158 case NET_EVENT_RESUME_IND:
160 /* think over what can we do... */
169 /*Definitions copied temperorily from ssl_unix.c */
170 #define SSLBUFLEN 8192
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 */
180 /*Definitions copied temperorily from ssl_unix.c - end*/
182 thread_t imap_idle_thread = NULL;
183 int g_imap_idle_thread_alive = 0;
186 int em_core_imap_idle_thread_create(int accountID, int *err_code)
188 EM_DEBUG_FUNC_BEGIN();
190 int thread_error = -1;
192 #ifdef ENABLE_IMAP_IDLE_THREAD
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)
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;
208 #else /* ENABLE_IMAP_IDLE_THREAD */
209 EM_DEBUG_LOG(">>>>>>>> DISABLED IMAP IDLE THREAD");
210 #endif /* ENABLE_IMAP_IDLE_THREAD */
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.
220 int em_core_imap_idle_thread_kill(int *err_code)
222 EM_DEBUG_FUNC_BEGIN();
224 int err = EMF_ERROR_NONE;
226 EM_DEBUG_LOG(">>>>>>>>>>>>killing thread>>>>>>>>>");
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");
233 EM_DEBUG_LOG(">>>>>>>>>>>>>>>>>> Making imap idle NULL>>>>>>>>>>>>>>>>>");
234 imap_idle_thread = NULL;
235 EM_DEBUG_LOG(">>>>>>>>>>>>>>>>>> killed IMAP IDLE >>>>>>>>>>>>>>>>>");
243 int em_core_imap_idle_run(int accountID)
245 EM_DEBUG_FUNC_BEGIN();
246 char *mailbox_list[3]; /* Temperory - To be modified to char ***/
248 emf_mailbox_t *mail_box_list = NULL;
249 emf_mailbox_t *curr_mailbox = NULL;
250 emf_mailbox_t *prev_mailbox = NULL;
252 emf_mailbox_tbl_t *local_mailbox = NULL;
253 int err = EMF_ERROR_NONE;
256 emf_session_t *session = NULL;
259 if ( !em_core_check_network_status(&err)) {
260 EM_DEBUG_EXCEPTION("em_core_check_network_status failed [%d]", err);
264 if (!em_storage_open(&err)) {
265 EM_DEBUG_EXCEPTION("\t em_storage_open falied - %d", err);
269 if (!em_core_get_empty_session(&session))
270 EM_DEBUG_EXCEPTION("\t em_core_get_empty_session failed...");
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 */
276 /* For testing - mailbox_num and mailbox_list are hardcoded here */
278 mailbox_list[0] = EM_SAFE_STRDUP("INBOX");
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);
288 curr_mailbox = em_core_malloc(sizeof(emf_mailbox_t));
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);
299 mail_box_list = curr_mailbox;
300 prev_mailbox = curr_mailbox;
306 prev_mailbox->next = curr_mailbox;
307 prev_mailbox = curr_mailbox;
314 if (local_mailbox != NULL)
315 em_storage_free_mailbox(&local_mailbox, 1, NULL);
319 em_core_clear_session(session);
321 em_core_imap_idle_loop_start(mail_box_list, num, NULL);
323 EM_DEBUG_EXCEPTION("IMAP IDLE ");
327 if (!em_storage_close(&err)) {
328 EM_DEBUG_EXCEPTION("\t em_storage_close falied - %d", err);
335 int em_core_imap_idle_loop_start(emf_mailbox_t *mailbox_list, int num, int *err_code)
337 EM_DEBUG_FUNC_BEGIN();
340 int err = EMF_ERROR_NONE;
342 int select_result = 0;
344 emf_mailbox_t *temp = NULL;
345 struct timeval timeout;
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);
351 err = EMF_ERROR_INVALID_PARAM;
355 /* set timeout value to 10min */
356 timeout.tv_sec = 10 * 60;
361 EM_DEBUG_EXCEPTION(">>>>>>>>>>>IDLING>>>>>>>>>>>>");
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;
373 select_result = select(maxfd, &readfds, NULL, NULL, &timeout);
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 ");
385 break; /* break for now - check if it is possible to get data on two sockets - shasikala.p */
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];
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;
403 sprintf(tag, "%08lx", 0xffffffff & (((MAILSTREAM *)temp->mail_stream)->gensym++));
404 sprintf(cmd, "%s DONE\015\012", tag);
406 if (!imap_local->netstream || !net_sout(imap_local->netstream, cmd, (int)strlen(cmd)))
408 EM_DEBUG_EXCEPTION("network error - failed to DONE on Mailbox - %s ", temp->name);
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);
424 /* kill idle thread */
425 em_core_imap_idle_thread_kill(&err);
431 might happen that a socket desciptor passed to select got closed
432 chack which got closed and make hold_connection 0
434 EM_DEBUG_EXCEPTION(">>>>>> socket desciptor error : No Data ");
443 EM_DEBUG_LOG(">>>> em_core_imap_idle_loop_start 17 ");
447 EM_DEBUG_EXCEPTION(">>>>>>> em_core_imap_idle_loop_start End ");
452 int em_core_imap_idle_insert_sync_event(emf_mailbox_t *mailbox, int *err_code)
454 EM_DEBUG_FUNC_BEGIN();
457 int err = EMF_ERROR_NONE;
460 if (!mailbox || mailbox->account_id <= 0) {
461 EM_DEBUG_LOG("\t mailbox[%p]", mailbox);
463 err = EMF_ERROR_INVALID_PARAM;
466 emf_event_t event_data;
467 memset(&event_data, 0x00, sizeof(emf_event_t));
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;
474 if (!em_core_insert_event(&event_data, &handle, &err)) {
475 EM_DEBUG_LOG("\t em_core_insert_event falied - %d", err);
477 /* err = EMF_ERROR_DB_FAILURE; */
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)
492 EM_DEBUG_FUNC_BEGIN();
493 void *mail_stream = NULL;
494 char cmd[128], tag[32], *p;
497 int err = EMF_ERROR_NONE;
498 emf_account_t *ref_account = NULL;
500 /* NULL param check */
502 EM_DEBUG_EXCEPTION("\t mailbox[%p]", mailbox);
504 *err_code = EMF_ERROR_INVALID_PARAM;
508 ref_account = em_core_get_account_reference(mailbox->account_id);
510 EM_DEBUG_EXCEPTION("\t em_core_get_account_reference failed - %d", mailbox->account_id);
512 err = EMF_ERROR_INVALID_ACCOUNT;
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);
524 IMAPLOCAL *imap_local = ((MAILSTREAM *)mail_stream)->local;
525 NETSTREAM *net_stream = imap_local->netstream;
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;
534 tcp_stream = net_stream->stream;
538 socket_id = ((TCPSTREAM *)tcp_stream)->tcpsi;
540 sprintf(tag, "%08lx", 0xffffffff & (((MAILSTREAM *)mail_stream)->gensym++));
541 sprintf(cmd, "%s IDLE\015\012", tag);
543 /* Send IDLE command */
544 if (!imap_local->netstream || !net_sout(imap_local->netstream, cmd, (int)strlen(cmd)))
546 EM_DEBUG_EXCEPTION("network error - failed to IDLE on Mailbox - %s ", mailbox->name);
548 *err_code = EMF_ERROR_IMAP4_IDLE_FAILURE;
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)) {
560 else if (!strncmp(p, "*", 1)) {
569 EM_SAFE_FREE(p); /* Prevent Defect - 18815 */
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 */
578 if (mail_stream) em_core_mailbox_close(mailbox->account_id, mail_stream);
583 int em_core_imap_idle_parse_response_stream(emf_mailbox_t *mailbox, int *err_code)
585 EM_DEBUG_FUNC_BEGIN();
586 int err = EMF_ERROR_NONE;
590 /* NULL PARAM CHECK */
592 EM_DEBUG_EXCEPTION("\t mailbox[%p]", mailbox);
594 *err_code = EMF_ERROR_INVALID_PARAM;
598 IMAPLOCAL *imap_local = NULL;
600 if (!mailbox->mail_stream){
601 EM_DEBUG_EXCEPTION("mail_stream is NULL");
605 imap_local = ((MAILSTREAM *)mailbox->mail_stream)->local;
608 EM_DEBUG_EXCEPTION("imap_local is NULL");
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");
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);
632 else if (p && (!strncmp(p, "+", 1))) {
633 /* Bad response from server */
634 EM_DEBUG_LOG("p is [%s]", p);
639 EM_DEBUG_LOG("In else part");
648 #endif /* _FEATURE_IMAP_IDLE */