Changeset 3801
- Timestamp:
- 11/10/08 15:08:37
- Files:
-
- releases/modest/diablo-pe2/ChangeLog (modified) (1 diff)
- releases/modest/diablo-pe2/libtinymail-camel/camel-lite/camel/camel-service.c (modified) (3 diffs)
- releases/modest/diablo-pe2/libtinymail-camel/camel-lite/camel/camel-service.h (modified) (3 diffs)
- releases/modest/diablo-pe2/libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-command.c (modified) (12 diffs)
- releases/modest/diablo-pe2/libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-folder.c (modified) (44 diffs)
- releases/modest/diablo-pe2/libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-folder.h (modified) (1 diff)
- releases/modest/diablo-pe2/libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-search.c (modified) (2 diffs)
- releases/modest/diablo-pe2/libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-store.c (modified) (60 diffs)
- releases/modest/diablo-pe2/libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-store.h (modified) (4 diffs)
- releases/modest/diablo-pe2/libtinymail-camel/tny-camel-queue.c (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
releases/modest/diablo-pe2/ChangeLog
r3799 r3801 1 1 2008-11-10 Jose Dapena Paz <jdapena@igalia.com> 2 3 Complete rework of the lock behavior of Tinymail 4 (camel) imap IDLE implementation. 5 6 The problem we want to fix is: sometimes IDLE thread causes 7 deathlocks (connect lock, idle lock, g_thread_join, etc). 8 This happens easily when there are disconnects, or 9 when we switch fast among folders. 10 11 The main changes are: 12 * Provided a count of reasons to stop idle because of connect lock. 13 * If a caller has taken connect lock, then it should do the send done 14 stuff itself. 15 * Idle thread has the connect lock always when it's in the body of the 16 loop. 17 * In any point, if we want to take the connect lock, then we should 18 stop idle. No partial idle can be alive when we want to connect. 19 * Camel queue enables/disables the possibility to start idle. That's 20 for avoiding running IDLE / SEND DONE in the middle of queued 21 operations. 2 22 3 23 * Specify with defines the IDLE tick time (time between iterations in releases/modest/diablo-pe2/libtinymail-camel/camel-lite/camel/camel-service.c
r3571 r3801 60 60 static gboolean service_disconnect(CamelService *service, gboolean clean, 61 61 CamelException *ex); 62 static void service_can_idle (CamelService *service, gboolean can_idle); 62 63 static void cancel_connect (CamelService *service); 63 64 static GList *query_auth_types (CamelService *service, CamelException *ex); … … 88 89 camel_service_class->get_name = get_name; 89 90 camel_service_class->get_path = get_path; 91 camel_service_class->can_idle = service_can_idle; 90 92 } 91 93 … … 770 772 return ret; 771 773 } 774 775 /** 776 * camel_service_can_idle: 777 * @service: a #CamelService 778 * @can_idle: a #gboolean 779 * 780 * Sets if service can do idle operations or not. This is for 781 * avoiding the service believe it can do idle operations in 782 * the middle of queued operations. 783 */ 784 void 785 camel_service_can_idle (CamelService *service, 786 gboolean can_idle) 787 { 788 g_return_val_if_fail (CAMEL_IS_SERVICE (service), NULL); 789 790 CSERV_CLASS (service)->can_idle (service, can_idle); 791 } 792 793 static void 794 service_can_idle (CamelService *service, 795 gboolean can_idle) 796 { 797 /* Default implementation is empty */ 798 } releases/modest/diablo-pe2/libtinymail-camel/camel-lite/camel/camel-service.h
r3088 r3801 74 74 gboolean reconnecting; 75 75 76 gboolean can_idle; 77 76 78 con_op connecting; 77 79 con_op disconnecting; … … 102 104 gboolean brief); 103 105 char * (*get_path) (CamelService *service); 106 void (*can_idle) (CamelService *service, gboolean can_idle); 104 107 105 108 } CamelServiceClass; … … 142 145 CamelException *ex); 143 146 147 void camel_service_can_idle (CamelService *service, 148 gboolean can_idle); 149 144 150 /* Standard Camel function */ 145 151 CamelType camel_service_get_type (void); releases/modest/diablo-pe2/libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-command.c
r3646 r3801 123 123 char *cmd = NULL; 124 124 125 CAMEL_SERVICE_REC_LOCK (store, connect_lock);125 camel_imap_store_stop_idle_connect_lock (store); 126 126 127 127 if (fmt) { … … 180 180 if (!imap_command_start (store, folder, cmd, ex)) { 181 181 g_free (cmd); 182 CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);182 camel_imap_store_connect_unlock_start_idle (store); 183 183 return NULL; 184 184 } … … 235 235 va_end (ap); 236 236 237 CAMEL_SERVICE_REC_LOCK (store, connect_lock);237 camel_imap_store_stop_idle_connect_lock (store); 238 238 239 239 ok = imap_command_start (store, folder, cmd, ex); … … 241 241 242 242 if (!ok) 243 CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);243 camel_imap_store_connect_unlock_start_idle (store); 244 244 245 245 return ok; … … 251 251 { 252 252 ssize_t nwritten; 253 ssize_t nread; 253 254 gchar *resp = NULL; 254 255 CamelException myex = CAMEL_EXCEPTION_INITIALISER; … … 355 356 356 357 /* Read away whatever we got */ 357 while ( camel_imap_store_readline_nb (store, &resp, &myex) > 0)358 while ((nread = camel_imap_store_readline_nb (store, &resp, &myex)) > 0) 358 359 { 360 #ifdef IMAP_DEBUG 361 gchar *debug_resp; 362 gchar *debug_resp_escaped; 359 363 imap_debug ("unsolitcited: "); 360 imap_debug (resp); 364 debug_resp = g_strndup (resp, nread); 365 debug_resp_escaped = g_strescape (debug_resp, ""); 366 g_free (debug_resp); 367 imap_debug (debug_resp_escaped); 368 g_free (debug_resp_escaped); 361 369 imap_debug ("\n"); 370 #endif 362 371 363 372 g_free (resp); … … 435 444 camel_imap_recon (store, &mex, TRUE); 436 445 imap_debug ("Recon in cont: %s\n", camel_exception_get_description (&mex)); 437 CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);446 camel_imap_store_connect_unlock_start_idle (store); 438 447 camel_exception_clear (&mex); 439 448 return NULL; … … 443 452 camel_service_disconnect (CAMEL_SERVICE (store), FALSE, NULL); 444 453 445 CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);454 camel_imap_store_connect_unlock_start_idle (store); 446 455 return NULL; 447 456 } … … 475 484 476 485 if (camel_imap_store_readline (store, &respbuf, ex) < 0) { 477 CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);486 camel_imap_store_connect_unlock_start_idle (store); 478 487 return CAMEL_IMAP_RESPONSE_ERROR; 479 488 } … … 538 547 if (type == CAMEL_IMAP_RESPONSE_ERROR || 539 548 type == CAMEL_IMAP_RESPONSE_TAGGED) 540 CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);549 camel_imap_store_connect_unlock_start_idle (store); 541 550 542 551 return type; … … 623 632 */ 624 633 625 CAMEL_SERVICE_REC_LOCK (store, connect_lock);634 camel_imap_store_stop_idle_connect_lock (store); 626 635 627 636 response = g_new0 (CamelImapResponse, 1); … … 1070 1079 g_free (response); 1071 1080 1072 CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);1081 camel_imap_store_connect_unlock_start_idle (store); 1073 1082 } 1074 1083 releases/modest/diablo-pe2/libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-folder.c
r3799 r3801 913 913 * should do it. */ 914 914 CAMEL_FOLDER_REC_LOCK(folder, lock); 915 CAMEL_SERVICE_REC_LOCK (imap_store, connect_lock);915 camel_imap_store_stop_idle_connect_lock (imap_store); 916 916 917 917 if (!camel_disco_store_check_online ((CamelDiscoStore*)imap_store, ex)) … … 958 958 } 959 959 done: 960 CAMEL_SERVICE_REC_UNLOCK (imap_store, connect_lock);961 CAMEL_FOLDER_REC_UNLOCK(folder, lock);962 963 960 camel_folder_summary_save(folder->summary, ex); 964 961 camel_store_summary_save((CamelStoreSummary *)((CamelImapStore *)folder->parent_store)->summary, ex); 965 962 966 camel_imap_folder_start_idle (folder); 963 camel_imap_store_connect_unlock_start_idle (imap_store); 964 CAMEL_FOLDER_REC_UNLOCK(folder, lock); 967 965 968 966 } … … 1498 1496 1499 1497 camel_exception_init (&local_ex); 1500 CAMEL_SERVICE_REC_LOCK (store, connect_lock);1498 camel_imap_store_stop_idle_connect_lock (store); 1501 1499 1502 1500 /* Find a message with changed flags, find all of the other … … 1564 1562 g_ptr_array_free (matches, TRUE); 1565 1563 1566 /* We unlock here so that other threads can have a chance to grab the connect_lock */1567 CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);1568 1569 1564 /* check for an exception */ 1570 1565 if (camel_exception_is_set (&local_ex)) { 1571 1566 1567 camel_imap_store_connect_unlock_start_idle (store); 1568 1572 1569 camel_exception_xfer (ex, &local_ex); 1573 camel_imap_folder_start_idle (folder);1574 1570 return; 1575 1571 } 1576 1572 1577 /* Re-lock the connect_lock */1578 CAMEL_SERVICE_REC_LOCK (store, connect_lock);1579 1573 } 1580 1574 … … 1582 1576 imap_sync_offline (folder, ex); 1583 1577 1584 CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);1578 camel_imap_store_connect_unlock_start_idle (store); 1585 1579 camel_imap_folder_start_idle (folder); 1586 1580 … … 1636 1630 char *set; 1637 1631 1638 CAMEL_SERVICE_REC_LOCK (store, connect_lock);1632 camel_imap_store_stop_idle_connect_lock (store); 1639 1633 1640 1634 if ((store->capabilities & IMAP_CAPABILITY_UIDPLUS) == 0) { 1641 1635 ((CamelFolderClass *)CAMEL_OBJECT_GET_CLASS(folder))->sync(folder, 0, ex); 1642 1636 if (camel_exception_is_set(ex)) { 1643 CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);1637 camel_imap_store_connect_unlock_start_idle (store); 1644 1638 return; 1645 1639 } … … 1656 1650 camel_imap_response_free (store, response); 1657 1651 if (camel_exception_is_set (ex)) { 1658 CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);1652 camel_imap_store_connect_unlock_start_idle (store); 1659 1653 g_free (set); 1660 1654 return; … … 1683 1677 } 1684 1678 1685 CAMEL_SERVICE_REC_UNLOCK (store, connect_lock); 1686 1687 camel_imap_folder_start_idle (folder); 1688 1679 camel_imap_store_connect_unlock_start_idle (store); 1689 1680 } 1690 1681 … … 1711 1702 * marked un-deleted. */ 1712 1703 1713 CAMEL_SERVICE_REC_LOCK (store, connect_lock);1704 camel_imap_store_stop_idle_connect_lock (store); 1714 1705 1715 1706 ((CamelFolderClass *)CAMEL_OBJECT_GET_CLASS(folder))->sync(folder, 0, ex); 1716 1707 if (camel_exception_is_set(ex)) { 1717 CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);1708 camel_imap_store_connect_unlock_start_idle (store); 1718 1709 return; 1719 1710 } … … 1726 1717 result = camel_imap_response_extract (store, response, "SEARCH", ex); 1727 1718 if (!result) { 1728 CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);1719 camel_imap_store_connect_unlock_start_idle (store); 1729 1720 return; 1730 1721 } … … 1786 1777 g_ptr_array_free (keep_uids, TRUE); 1787 1778 g_ptr_array_free (mark_uids, TRUE); 1788 CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);1779 camel_imap_store_connect_unlock_start_idle (store); 1789 1780 return; 1790 1781 } … … 1811 1802 g_ptr_array_free (keep_uids, TRUE); 1812 1803 g_ptr_array_free (mark_uids, TRUE); 1804 camel_imap_store_connect_unlock_start_idle (store); 1813 1805 CAMEL_SERVICE_REC_UNLOCK (store, connect_lock); 1814 1806 return; … … 1850 1842 g_free (result); 1851 1843 1852 CAMEL_SERVICE_REC_UNLOCK (store, connect_lock); 1853 1854 camel_imap_folder_start_idle (folder); 1844 camel_imap_store_connect_unlock_start_idle (store); 1855 1845 1856 1846 } … … 2043 2033 2044 2034 /* Make sure a "folder_changed" is emitted. */ 2045 CAMEL_SERVICE_REC_LOCK (store, connect_lock);2035 camel_imap_store_stop_idle_connect_lock (store); 2046 2036 if (store->current_folder != folder || 2047 2037 camel_folder_summary_count (folder->summary) == count) 2048 2038 imap_refresh_info (folder, ex); 2049 CAMEL_SERVICE_REC_UNLOCK (store, connect_lock); 2050 2051 camel_imap_folder_start_idle (folder); 2039 camel_imap_store_connect_unlock_start_idle (store); 2052 2040 2053 2041 } … … 2105 2093 * to copy messages in the other direction from another thread. 2106 2094 */ 2107 CAMEL_SERVICE_REC_LOCK (store, connect_lock);2095 camel_imap_store_stop_idle_connect_lock (store); 2108 2096 CAMEL_IMAP_FOLDER_REC_LOCK (source, cache_lock); 2109 2097 CAMEL_IMAP_FOLDER_REC_LOCK (dest, cache_lock); 2110 CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);2098 camel_imap_store_connect_unlock_start_idle (store); 2111 2099 2112 2100 if (transferred_uids) { … … 2812 2800 int i; 2813 2801 2814 CAMEL_SERVICE_REC_LOCK(store, connect_lock);2802 camel_imap_store_stop_idle_connect_lock (store); 2815 2803 if (!camel_disco_store_check_online ((CamelDiscoStore*)store, ex)) { 2816 CAMEL_SERVICE_REC_UNLOCK(store, connect_lock);2804 camel_imap_store_connect_unlock_start_idle (store); 2817 2805 camel_exception_set (ex, CAMEL_EXCEPTION_FOLDER_UID_NOT_AVAILABLE, 2818 2806 _("This message is not currently available")); … … 2821 2809 2822 2810 response = camel_imap_command (store, folder, ex, "UID FETCH %s BODY", uid); 2823 CAMEL_SERVICE_REC_UNLOCK(store, connect_lock);2811 camel_imap_store_connect_unlock_start_idle (store); 2824 2812 2825 2813 if (response) { … … 3369 3357 if (tcnt < (exists - seq)) 3370 3358 { 3371 int i;3372 3359 3373 3360 g_ptr_array_foreach (needheaders, (GFunc)g_free, NULL); … … 3878 3865 } 3879 3866 3867 static void 3868 process_idle_body (CamelImapStore *store, CamelFolder *folder, IdleResponse **idle_response, CamelException *exception) 3869 { 3870 char *resp = NULL; 3871 3872 while (camel_imap_store_readline_nb (store, &resp, exception) > 0) { 3873 if (resp && strlen (resp) > 1 && resp[0] == '*') { 3874 if (!*idle_response) 3875 *idle_response = idle_response_new (folder); 3876 consume_idle_line (store, folder, resp, *idle_response); 3877 } 3878 3879 if (resp) 3880 g_free (resp); 3881 resp = NULL; 3882 } 3883 } 3884 3885 static void 3886 process_idle_untagged_response (CamelImapStore *store, CamelFolder *folder, IdleResponse **idle_response, CamelException *exception) 3887 { 3888 char *resp = NULL; 3889 CamelImapResponseType type; 3890 3891 while ((type = camel_imap_command_response_idle (store, &resp, exception)) == CAMEL_IMAP_RESPONSE_UNTAGGED) { 3892 if (resp && strlen (resp) > 1 && resp[0] == '*') { 3893 if (!*idle_response) 3894 *idle_response = idle_response_new (folder); 3895 consume_idle_line (store, folder, resp, *idle_response); 3896 } 3897 3898 if (resp) 3899 g_free (resp); 3900 resp = NULL; 3901 } 3902 } 3903 3904 static void 3905 do_send_done (CamelImapStore *store, CamelFolder *folder, IdleResponse **idle_resp, CamelException *ex) 3906 { 3907 if (store->idle_prefix) { 3908 gboolean l = g_static_rec_mutex_trylock (store->idle_lock); 3909 3910 if (!store->idle_kill) { 3911 int nwritten=0; 3912 /* We read-away everything that we still 3913 * have. To find where idle_resp is handled, 3914 * read below at the g_thread_join for 3915 * this thread (we are returning it). */ 3916 3917 process_idle_body (store, folder, idle_resp, ex); 3918 3919 /* We send the DONE to the server */ 3920 3921 nwritten = camel_stream_printf (store->ostream, "DONE\r\n"); 3922 idle_debug ("(%d, 8) -> DONE\n", nwritten); 3923 3924 /* We read away everything the server sends 3925 * until the we see the untagged OK response */ 3926 3927 process_idle_untagged_response (store, folder, idle_resp, ex); 3928 } 3929 3930 if (l) 3931 g_static_rec_mutex_unlock (store->idle_lock); 3932 3933 /* If we are continuing the loop, handle idle_resp 3934 * now (this can invoke fetching new headers). */ 3935 3936 if (store->idle_cont && *idle_resp) { 3937 process_idle_response (*idle_resp); 3938 idle_response_free (*idle_resp); 3939 *idle_resp = NULL; 3940 } 3941 3942 } 3943 store->idle_send_done_happened = TRUE; 3944 } 3945 3946 static gpointer 3947 send_done_in_stop_idle (CamelImapStore *store, CamelFolder *folder) 3948 { 3949 CamelException ex = CAMEL_EXCEPTION_INITIALISER; 3950 IdleResponse *idle_resp = NULL; 3951 3952 /* This method is used for sending the commands we expect idle thread to do to finish 3953 * idle loop, when the caller thread has the connect lock (and then the idle thread cannot 3954 * do safely these commands */ 3955 3956 if (g_static_rec_mutex_trylock (store->idle_lock)) { 3957 /* Step B) (see idle_thread) */ 3958 3959 if (!store->idle_kill) { 3960 process_idle_body (store, folder, &idle_resp, &ex); 3961 } 3962 g_static_rec_mutex_unlock (store->idle_lock); 3963 } 3964 3965 /* Step C) (see idle_thread). We're assuming idle_cont == FALSE, send_done == TRUE*/ 3966 do_send_done (store, folder, &idle_resp, &ex); 3967 return idle_resp; 3968 } 3969 3880 3970 typedef struct { 3881 3971 CamelFolder *folder; … … 3894 3984 gboolean tfirst = TRUE, first = TRUE, my_cont, had_cond = FALSE; 3895 3985 int cnt = 0; 3896 int nwritten=0;3897 3986 gpointer retval = NULL; 3898 3987 … … 3957 4046 } 3958 4047 4048 store->idle_send_done_happened = FALSE; 3959 4049 /* While nothing has stopped us yet ... 3960 4050 * TNY TODO: it would be nicer to use select() here, rather than usleep() */ 3961 3962 while (my_cont && !store->idle_kill) 4051 4052 while (my_cont && !store->idle_kill && 4053 (store->idle_cont || !store->idle_send_done_happened)) 3963 4054 { 3964 4055 CamelException ex = CAMEL_EXCEPTION_INITIALISER; 3965 char *resp = NULL;3966 4056 IdleResponse *idle_resp = NULL; 3967 4057 gboolean senddone = FALSE; 3968 3969 /* A) The first time we will start the IDLE by sending IDLE to 3970 * the server and reading away the + continuation (check out the 3971 * idle_real_start function). We don't call this in the other 3972 * loop cycles of this while. */ 3973 3974 if (store->idle_cont && first) { 3975 gboolean l = g_static_rec_mutex_trylock (store->idle_lock); 3976 if (!store->idle_kill) 3977 idle_real_start (store); 3978 if (l) 3979 g_static_rec_mutex_unlock (store->idle_lock); 3980 first = FALSE; 3981 } 3982 3983 /* And we also send the broadcast to the caller of this thread: 3984 * We're started, and we're fine. It can continue. We don't call 3985 * this in the other loop cycles of this while. */ 3986 3987 if (tfirst) { 3988 if (info->condition) { 3989 g_mutex_lock (info->mutex); 3990 g_cond_broadcast (info->condition); 3991 info->had_cond = TRUE; had_cond = TRUE; 3992 g_mutex_unlock (info->mutex); 3993 } 3994 tfirst = FALSE; 3995 } 3996 3997 if (g_static_rec_mutex_trylock (store->idle_lock)) 3998 { 3999 /* B) This happens during the IDLE's body (after IDLE is 4000 * started and before DONE is sent). We read away the 4001 * lines in a non-blocking way. As soon as we have a 4002 * full line, that starts with '*', we consume it. */ 4003 4004 if (!store->idle_kill) { 4005 while (camel_imap_store_readline_nb (store, &resp, &ex) > 0) 4006 { 4007 if (resp && strlen (resp) > 1 && resp[0] == '*') { 4008 if (!idle_resp) 4009 idle_resp = idle_response_new (folder); 4010 consume_idle_line (store, folder, resp, idle_resp); 4011 } 4012 4013 if (resp) 4014 g_free (resp); 4015 resp = NULL; 4016 } 4017 } 4018 g_static_rec_mutex_unlock (store->idle_lock); 4019 } 4020 4021 if (resp) 4022 g_free (resp); 4023 4024 if (store->idle_cont) 4025 { 4026 if (idle_resp && !idle_resp->exists_happened) { 4027 /* We can process it already: nothing is at this moment 4028 * joining us, nothing is at this moment locking the 4029 * folder_changed handler of TnyCamelFolder */ 4030 process_idle_response (idle_resp); 4031 idle_response_free (idle_resp); 4032 idle_resp = NULL; 4033 retval = NULL; 4034 } else if (idle_resp && idle_resp->exists_happened) { 4035 4036 /* We can't deal with new EXISTS responses 4037 * without first stopping IDLE (we'll need to 4038 * fetch the new headers) */ 4039 4040 senddone = TRUE; 4041 retval = idle_resp; 4042 } 4043 } else { 4044 /* If store->idle_cont was FALSE, we're going to handle 4045 * idle_resp differently (look below). */ 4046 senddone = TRUE; 4047 retval = idle_resp; 4048 } 4049 4050 /* C) So either we timed out (store->idle_sleep as been reached), 4051 * which means that we 'are' going to restart this entire while, 4052 * including resending the IDLE-start, after we're done with 4053 * this if-block of course. 4054 * 4055 * Or another thread called us to stop IDLE, and then we're 4056 * going to exit this while, of course. If it was an idle_kill, 4057 * we're not even going to try doing that in a nice way. In that 4058 * case we'll just exit ASAP (it's let_idle_die in CamelImapStore 4059 * trying to disconnect from the IMAP server). */ 4060 4061 if ((cnt > store->idle_sleep) || senddone) 4062 { 4063 if (store->idle_prefix) 4064 { 4065 CamelImapResponseType type; 4058 4059 if (CAMEL_SERVICE_REC_TRYLOCK (store, connect_lock)) { 4060 /* A) The first time we will start the IDLE by sending IDLE to 4061 * the server and reading away the + continuation (check out the 4062 * idle_real_start function). We don't call this in the other 4063 * loop cycles of this while. */ 4064 4065 if (store->idle_cont && first) { 4066 4066 gboolean l = g_static_rec_mutex_trylock (store->idle_lock); 4067 4068 4067 if (!store->idle_kill) 4069 { 4070 /* We read-away everything that we still 4071 * have. To find where idle_resp is handled, 4072 * read below at the g_thread_join for 4073 * this thread (we are returning it). */ 4074 4075 resp = NULL; 4076 while (camel_imap_store_readline_nb (store, &resp, &ex) > 0) 4077 { 4078 if (resp && strlen (resp) > 1 && resp[0] == '*') { 4079 if (!idle_resp) { 4080 idle_resp = idle_response_new (folder); 4081 /* We will free this after the join */ 4082 if (!store->idle_cont) 4083 retval = idle_resp; 4084 } 4085 consume_idle_line (store, folder, resp, idle_resp); 4086 } 4087 4088 if (resp) 4089 g_free (resp); 4090 resp = NULL; 4091 } 4092 if (resp) 4093 g_free (resp); 4094 resp = NULL; 4095 4096 /* We send the DONE to the server */ 4097 4098 nwritten = camel_stream_printf (store->ostream, "DONE\r\n"); 4099 idle_debug ("(%d, 8) -> DONE\n", nwritten); 4100 4101 /* We read away everything the server sends 4102 * until the we see the untagged OK response */ 4103 4104 while ((type = camel_imap_command_response_idle (store, &resp, &ex)) == CAMEL_IMAP_RESPONSE_UNTAGGED) 4105 { 4106 if (resp && strlen (resp) > 1 && resp[0] == '*') { 4107 if (!idle_resp) { 4108 idle_resp = idle_response_new (folder); 4109 /* We will free this after the join */ 4110 if (!store->idle_cont) 4111 retval = idle_resp; 4112 } 4113 consume_idle_line (store, folder, resp, idle_resp); 4114 } 4115 4116 if (resp) 4117 g_free (resp); 4118 resp = NULL; 4119 } 4120 } 4121 4068 idle_real_start (store); 4122 4069 if (l) 4123 4070 g_static_rec_mutex_unlock (store->idle_lock); 4124 4125 if (resp) 4126 g_free (resp); 4127 resp = NULL; 4128 4129 /* If we are continuing the loop, handle idle_resp 4130 * now (this can invoke fetching new headers). */ 4131 4132 if (store->idle_cont && idle_resp) { 4071 first = FALSE; 4072 } 4073 4074 /* And we also send the broadcast to the caller of this thread: 4075 * We're started, and we're fine. It can continue. We don't call 4076 * this in the other loop cycles of this while. */ 4077 4078 if (tfirst) { 4079 if (info->condition) { 4080 g_mutex_lock (info->mutex); 4081 g_cond_broadcast (info->condition); 4082 info->had_cond = TRUE; had_cond = TRUE; 4083 g_mutex_unlock (info->mutex); 4084 } 4085 tfirst = FALSE; 4086 } 4087 4088 if (g_static_rec_mutex_trylock (store->idle_lock)) { 4089 /* B) This happens during the IDLE's body (after IDLE is 4090 * started and before DONE is sent). We read away the 4091 * lines in a non-blocking way. As soon as we have a 4092 * full line, that starts with '*', we consume it. */ 4093 4094 if (!store->idle_kill) { 4095 process_idle_body (store, folder, &idle_resp, &ex); 4096 } 4097 g_static_rec_mutex_unlock (store->idle_lock); 4098 } 4099 4100 if (store->idle_cont) { 4101 if (idle_resp && !idle_resp->exists_happened) { 4102 /* We can process it already: nothing is at this moment 4103 * joining us, nothing is at this moment locking the 4104 * folder_changed handler of TnyCamelFolder */ 4133 4105 process_idle_response (idle_resp); 4134 4106 idle_response_free (idle_resp); 4135 4107 idle_resp = NULL; 4136 4108 retval = NULL; 4109 } else if (idle_resp && idle_resp->exists_happened) { 4110 4111 /* We can't deal with new EXISTS responses 4112 * without first stopping IDLE (we'll need to 4113 * fetch the new headers) */ 4114 4115 senddone = TRUE; 4116 retval = idle_resp; 4137 4117 } 4138 } 4139 4140 if (store->idle_cont) 4141 first = TRUE; 4142 else 4143 my_cont = FALSE; 4118 } else { 4119 /* If store->idle_cont was FALSE, we're going to handle 4120 * idle_resp differently (look below). */ 4121 senddone = TRUE; 4122 retval = idle_resp; 4123 } 4124 4125 /* C) So either we timed out (store->idle_sleep as been reached), 4126 * which means that we 'are' going to restart this entire while, 4127 * including resending the IDLE-start, after we're done with 4128 * this if-block of course. 4129 * 4130 * Or another thread called us to stop IDLE, and then we're 4131 * going to exit this while, of course. If it was an idle_kill, 4132 * we're not even going to try doing that in a nice way. In that 4133
