From e80ec4cc5f68fd07cb25792017ea3fa3c78c398b Mon Sep 17 00:00:00 2001 From: Brenden Matthews Date: Thu, 25 Sep 2008 03:11:24 +0000 Subject: [PATCH] improving IMAP IDLE support git-svn-id: https://conky.svn.sourceforge.net/svnroot/conky/trunk/conky1@1257 7f574dfc-610e-0410-a909-a81674777703 --- src/conky.c | 135 ++++++++++++++++----------------------------- src/timed_thread.c | 16 ++++++ src/timed_thread.h | 3 + 3 files changed, 67 insertions(+), 87 deletions(-) diff --git a/src/conky.c b/src/conky.c index d2878a00..812d088c 100644 --- a/src/conky.c +++ b/src/conky.c @@ -1647,6 +1647,33 @@ struct mail_s *parse_mail_args(char type, const char *arg) return mail; } +int imap_command(int sockfd, char *command, char *response, const char *verify) +{ + struct timeval timeout; + fd_set fdset; + int res, numbytes; + if (send(sockfd, command, strlen(command), 0) == -1) { + perror("send"); + return -1; + } + timeout.tv_sec = 60; // 60 second timeout i guess + timeout.tv_usec = 0; + FD_ZERO(&fdset); + FD_SET(sockfd, &fdset); + res = select(sockfd + 1, &fdset, NULL, NULL, &timeout); + if (res > 0) { + if ((numbytes = recv(sockfd, response, MAXDATASIZE - 1, 0)) == -1) { + perror("recv"); + return -1; + } + } + response[numbytes] = '\0'; + if (strstr(response, verify) == NULL) { + return -1; + } + return 0; +} + void *imap_thread(void *arg) { int sockfd, numbytes; @@ -1663,6 +1690,7 @@ void *imap_thread(void *arg) struct sockaddr_in their_addr; // connector's address information struct mail_s *mail = (struct mail_s *)arg; int has_idle = 0; + int threadfd = timed_thread_readfd(mail->p_timed_thread); #ifdef HAVE_GETHOSTBYNAME_R if (gethostbyname_r(mail->host, &he, hostbuff, sizeof(hostbuff), &he_res, &he_errno)) { // get the host info @@ -1733,26 +1761,7 @@ void *imap_thread(void *arg) strncat(sendbuf, " ", MAXDATASIZE - strlen(sendbuf) - 1); strncat(sendbuf, mail->pass, MAXDATASIZE - strlen(sendbuf) - 1); strncat(sendbuf, "\r\n", MAXDATASIZE - strlen(sendbuf) - 1); - if (send(sockfd, sendbuf, strlen(sendbuf), 0) == -1) { - perror("send a1"); - fail++; - break; - } - timeout.tv_sec = 60; // 60 second timeout i guess - timeout.tv_usec = 0; - FD_ZERO(&fdset); - FD_SET(sockfd, &fdset); - res = select(sockfd + 1, &fdset, NULL, NULL, &timeout); - if (res > 0) { - if ((numbytes = recv(sockfd, recvbuf, MAXDATASIZE - 1, 0)) == -1) { - perror("recv a1"); - fail++; - break; - } - } - recvbuf[numbytes] = '\0'; - if (strstr(recvbuf, "a1 OK") == NULL) { - ERR("IMAP server login failed: %s", recvbuf); + if (imap_command(sockfd, sendbuf, recvbuf, "a1 OK")) { fail++; break; } @@ -1764,26 +1773,7 @@ void *imap_thread(void *arg) strncat(sendbuf, mail->folder, MAXDATASIZE - strlen(sendbuf) - 1); strncat(sendbuf, " (MESSAGES UNSEEN)\r\n", MAXDATASIZE - strlen(sendbuf) - 1); - if (send(sockfd, sendbuf, strlen(sendbuf), 0) == -1) { - perror("send a2"); - fail++; - break; - } - timeout.tv_sec = 60; // 60 second timeout i guess - timeout.tv_usec = 0; - FD_ZERO(&fdset); - FD_SET(sockfd, &fdset); - res = select(sockfd + 1, &fdset, NULL, NULL, &timeout); - if (res > 0) { - if ((numbytes = recv(sockfd, recvbuf, MAXDATASIZE - 1, 0)) == -1) { - perror("recv a2"); - fail++; - break; - } - } - recvbuf[numbytes] = '\0'; - if (strstr(recvbuf, "a2 OK") == NULL) { - ERR("IMAP status failed: %s", recvbuf); + if (imap_command(sockfd, sendbuf, recvbuf, "a2 OK")) { fail++; break; } @@ -1817,51 +1807,13 @@ void *imap_thread(void *arg) strncpy(sendbuf, "a4 SELECT ", MAXDATASIZE); strncat(sendbuf, mail->folder, MAXDATASIZE - strlen(sendbuf) - 1); strncat(sendbuf, "\r\n", MAXDATASIZE - strlen(sendbuf) - 1); - if (send(sockfd, sendbuf, strlen(sendbuf), 0) == -1) { - perror("send a4"); - fail++; - break; - } - timeout.tv_sec = 60; // 60 second timeout i guess - timeout.tv_usec = 0; - FD_ZERO(&fdset); - FD_SET(sockfd, &fdset); - res = select(sockfd + 1, &fdset, NULL, NULL, &timeout); - if (res > 0) { - if ((numbytes = recv(sockfd, recvbuf, MAXDATASIZE - 1, 0)) == -1) { - perror("recv a4"); - fail++; - break; - } - } - recvbuf[numbytes] = '\0'; - if (strstr(recvbuf, "a4 OK") == NULL) { - ERR("IMAP status failed: %s", recvbuf); + if (imap_command(sockfd, sendbuf, recvbuf, "a4 OK")) { fail++; break; } strncpy(sendbuf, "a5 IDLE\r\n", MAXDATASIZE); - if (send(sockfd, sendbuf, strlen(sendbuf), 0) == -1) { - perror("send a5"); - fail++; - break; - } - timeout.tv_sec = 60; // 60 second timeout i guess - timeout.tv_usec = 0; - FD_ZERO(&fdset); - FD_SET(sockfd, &fdset); - res = select(sockfd + 1, &fdset, NULL, NULL, &timeout); - if (res > 0) { - if ((numbytes = recv(sockfd, recvbuf, MAXDATASIZE - 1, 0)) == -1) { - perror("recv a5"); - fail++; - break; - } - } - recvbuf[numbytes] = '\0'; - if (strstr(recvbuf, "+ idling") == NULL) { - ERR("IMAP status failed: %s", recvbuf); + if (imap_command(sockfd, sendbuf, recvbuf, "+ idling")) { fail++; break; } @@ -1870,17 +1822,17 @@ void *imap_thread(void *arg) while (1) { FD_ZERO(&fdset); FD_SET(sockfd, &fdset); + FD_SET(threadfd, &fdset); + res = pselect(MAX(sockfd + 1, threadfd + 1), &fdset, NULL, NULL, NULL, &oldmask); if (timed_thread_test(mail->p_timed_thread)) { - break; + timed_thread_exit(mail->p_timed_thread); } - res = pselect(sockfd + 1, &fdset, NULL, NULL, NULL, &oldmask); - if (res == -1 && errno == EINTR) { + if ((res == -1 && errno == EINTR) || FD_ISSET(threadfd, &fdset)) { timed_thread_exit(mail->p_timed_thread); } else if (res > 0) { if ((numbytes = recv(sockfd, recvbuf, MAXDATASIZE - 1, 0)) == -1) { perror("recv idling"); fail++; - printf("fail\n"); break; } } else { @@ -1888,9 +1840,12 @@ void *imap_thread(void *arg) } recvbuf[numbytes] = '\0'; if (strlen(recvbuf) > 2) { - unsigned long messages, unseen; + unsigned long messages, recent; char *buf = recvbuf; buf = strstr(buf, "EXISTS"); + while (buf && strlen(buf) > 1 && strstr(buf + 1, "EXISTS")) { + buf = strstr(buf + 1, "EXISTS"); + } if (buf) { // back up until we reach '*' while (buf >= recvbuf && buf[0] != '*') { @@ -1904,14 +1859,20 @@ void *imap_thread(void *arg) } buf = recvbuf; buf = strstr(buf, "RECENT"); + while (buf && strlen(buf) > 1 && strstr(buf + 1, "RECENT")) { + buf = strstr(buf + 1, "RECENT"); + } if (buf) { // back up until we reach '*' while (buf >= recvbuf && buf[0] != '*') { buf--; } - if (sscanf(buf, "* %lu RECENT\r\n", &unseen) == 1) { + if (sscanf(buf, "* %lu RECENT\r\n", &recent) == 1) { + /* + * if we have > 0 recent, re-check the unseen count + */ timed_thread_lock(mail->p_timed_thread); - mail->unseen = unseen; + mail->unseen = recent; timed_thread_unlock(mail->p_timed_thread); } } diff --git a/src/timed_thread.c b/src/timed_thread.c index 678d0ab2..8226d465 100644 --- a/src/timed_thread.c +++ b/src/timed_thread.c @@ -27,6 +27,7 @@ #include #include #include +#include #ifndef HAVE_CLOCK_GETTIME #include #endif @@ -47,6 +48,7 @@ struct _timed_thread { void *arg; /* thread function argument */ struct timespec interval_time; /* interval_usecs as a struct timespec */ struct timespec wait_time; /* absolute future time next timed_thread_test will wait until */ + int pipefd[2]; }; /* linked list of created threads */ @@ -59,6 +61,11 @@ typedef struct _timed_thread_list { static timed_thread_list *p_timed_thread_list_head = NULL; static timed_thread_list *p_timed_thread_list_tail = NULL; +int timed_thread_readfd(timed_thread *p_timed_thread) +{ + return p_timed_thread->pipefd[0]; +} + static int now(struct timespec *abstime) { #ifndef HAVE_CLOCK_GETTIME @@ -96,6 +103,11 @@ timed_thread *timed_thread_create(void *start_routine(void *), void *arg, return NULL; } + /* create thread pipe (used to tell threads to die) */ + if (pipe(p_timed_thread->pipefd)) { + return NULL; + } + /* init attributes, e.g. joinable thread */ pthread_attr_init(&p_timed_thread->thread_attr); pthread_attr_setdetachstate(&p_timed_thread->thread_attr, @@ -147,6 +159,7 @@ void timed_thread_destroy(timed_thread *p_timed_thread, pthread_mutex_lock(&p_timed_thread->runnable_mutex); pthread_cond_signal(&p_timed_thread->runnable_cond); pthread_mutex_unlock(&p_timed_thread->runnable_mutex); + write(p_timed_thread->pipefd[1], "die", 3); /* join the terminating thread */ if (p_timed_thread->thread) { @@ -236,6 +249,9 @@ void timed_thread_exit(timed_thread *p_timed_thread) { assert(p_timed_thread != NULL); + close(p_timed_thread->pipefd[0]); + close(p_timed_thread->pipefd[1]); + pthread_exit(NULL); } diff --git a/src/timed_thread.h b/src/timed_thread.h index b6c0f051..9ff26c1d 100644 --- a/src/timed_thread.h +++ b/src/timed_thread.h @@ -63,4 +63,7 @@ int timed_thread_register(timed_thread *p_timed_thread, /* destroy all registered timed threads */ void timed_thread_destroy_registered_threads(void); +/* returns read file descriptor for thread pipe */ +int timed_thread_readfd(timed_thread *p_timed_thread); + #endif /* #ifdef _TIMED_THREAD_H_ */