X-Git-Url: http://gitweb.hugovil.com/?a=blobdiff_plain;f=src%2Fimap.c;h=61f83b8fafebf64cefcc09765af27ab00f623a86;hb=a6c4c0c8d8224cdc455f0d184e91d0cf881f0077;hp=da11e473e11052801434cf41bd56a783ebbdc4e7;hpb=36eddd2c06ce9b09c83102353deb213e065e901d;p=dockapps%2Fwmnotify.git diff --git a/src/imap.c b/src/imap.c index da11e47..61f83b8 100644 --- a/src/imap.c +++ b/src/imap.c @@ -34,7 +34,7 @@ #include #include #include -#include /* for isdigit() */ +#include /* for isdigit() */ #include "common.h" #include "wmnotify.h" @@ -42,7 +42,7 @@ #include "imap.h" -#define IMAP4_ENDL "\r\n" /* CRLF */ +#define IMAP4_ENDL "\r\n" /* CRLF */ #define IMAP4_CMD_CAPABILITY "CAPABILITY" #define IMAP4_CMD_LOGIN "LOGIN" @@ -55,13 +55,16 @@ #define IMAP4_RSP_SUCCESS "OK" #define IMAP4_RSP_FAILURE "NO" #define IMAP4_RSP_PROTOCOL_ERR "BAD" -#define IMAP4_RSP_SEARCH_UNSEEN "* SEARCH " /* This is the line that will be returned by - * the IMAP4 server after receiving the - * "SEARCH UNSEEN" command, followed by the - * messages ID of the unseen messages. */ - - -static int tlabel = 0; +#define IMAP4_RSP_SEARCH_UNSEEN "* SEARCH " /* + * This is the line that will be + * returned by the IMAP4 server + * after receiving the + * "SEARCH UNSEEN" command, followed + * by the messages ID of the unseen + * messages. + */ + +static int tlabel; static int tlabel_len; static int unseen_string_found; @@ -69,241 +72,289 @@ static int unseen_string_found; extern char tx_buffer[WMNOTIFY_BUFSIZE + 1]; extern char rx_buffer[WMNOTIFY_BUFSIZE + 1]; - -static int -IMAP4_ReceiveResponse( void ) +static int IMAP4_ReceiveResponse(void) { - int len; - char *token; - char *stringp; - - /* All interactions transmitted by client and server are in the form of - lines, that is, strings that end with a CRLF. The protocol receiver - of an IMAP4rev1 client or server is either reading a line, or is - reading a sequence of octets with a known count followed by a line. */ - - get_packet: - len = WmnotifyGetResponse( rx_buffer, WMNOTIFY_BUFSIZE ); - if( len < 0 ) { - /* An error occured. WmnotifyGetResponse() should have printed an error message. */ - goto error; - } - else if( len == 0 ) { - /* The return value will be 0 when the peer has performed an orderly shutdown. */ - if( wmnotify_infos.debug ) { - fprintf( stderr, "IMAP server has closed connection.\n" ); - } - goto error; - } - else if( len == WMNOTIFY_BUFSIZE ) { - if( wmnotify_infos.debug ) { - ErrorLocation( __FILE__, __LINE__ ); - fprintf( stderr, "Response too big (%d bytes) to fit in receive buffer.\n", len ); - } - goto error; - } - - /* We suppose that, if a partial response packet was sent, it is not broken in the middle - of a line (to confirm). Normally, each string is terminated by CRLF. */ - if( STREQ_LEN( &rx_buffer[ len - 2 ], IMAP4_ENDL, 2 ) == false ) { - /* No CRLF found at the end of the buffer --> not handled by wmnotify. */ - ErrorLocation( __FILE__, __LINE__ ); - fprintf( stderr, "Response buffer doesn't contain CRLF at the end.\n" ); - goto error; - } - - if( wmnotify_infos.debug ) { - printf( "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n" ); - printf( "IMAP4 Server Response (size %d bytes):\n", len ); - printf( "%s", rx_buffer ); - printf( "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n" ); - } - - /* Converting the last CRLF into a LF followed by a NULL termination character. */ - rx_buffer[ len - 2 ] = '\n'; - rx_buffer[ len - 1 ] = '\0'; - - /* Check the Server Completion Response returned by the IMAP4 server. There are currently - * three Server Completion Responses codes: success ("OK"), failure ("NO") and protocol error - * ("BAD"). */ - stringp = rx_buffer; - - while( ( token = strsep( &stringp, "\n" ) ) != NULL ) { - - /* In case no delimiter was found, the token is taken to - be the entire string *stringp, and *stringp is made NULL. */ - if( stringp == NULL ) { - if( token[0] == '\0' ) { - /* This means we finished parsing the last line of the buffer, but we need to - get more data to continue process the next part of the IMAP4 response. */ - goto get_packet; - } - else { - /* This should never happen. */ - ErrorLocation( __FILE__, __LINE__ ); - fprintf( stderr, " Delimiter not found in strsep() call.\n" ); - goto error; - } - } - - if( token == NULL ) { - /* This should never happen. */ - ErrorLocation( __FILE__, __LINE__ ); - fprintf( stderr, " NULL token returned by strsep().\n" ); - goto error; - } - - if( token[0] == '*' ) { - /* Untagged response. If there is a space after the SEARCH response, it means - * at least 1 message is unseen. */ - if( STREQ_LEN( token, IMAP4_RSP_SEARCH_UNSEEN, strlen(IMAP4_RSP_SEARCH_UNSEEN) ) == true ) { - unseen_string_found = true; - } - } - else { - /* Must be the status... */ - - /* We check for the correct transaction label plus a space. */ - if( STREQ_LEN( token, tx_buffer, tlabel_len + 1 ) == true ) { - token += tlabel_len + 1; - if( STREQ_LEN( token, IMAP4_RSP_SUCCESS, strlen(IMAP4_RSP_SUCCESS) ) == true ) { - goto end; /* OK, no errors. */ + int len; + char *token; + char *stringp; + + /* + * All interactions transmitted by client and server are in the form of + * lines, that is, strings that end with a CRLF. The protocol receiver + * of an IMAP4rev1 client or server is either reading a line, or is + * reading a sequence of octets with a known count followed by a line. + */ + +get_packet: + len = WmnotifyGetResponse(rx_buffer, WMNOTIFY_BUFSIZE); + if (len < 0) { + /* + * An error occured. WmnotifyGetResponse() should have printed + * an error message. + */ + goto error; + } else if (len == 0) { + /* + * The return value will be 0 when the peer has performed an + * orderly shutdown. + */ + if (wmnotify_infos.debug) { + fprintf(stderr, + "IMAP server has closed connection.\n"); + } + goto error; + } else if (len == WMNOTIFY_BUFSIZE) { + if (wmnotify_infos.debug) { + ErrorLocation(__FILE__, __LINE__); + fprintf(stderr, + "Response too big (%d bytes) to fit in receive buffer.\n", + len); + } + goto error; } - else if( STREQ_LEN( token, IMAP4_RSP_PROTOCOL_ERR, strlen(IMAP4_RSP_PROTOCOL_ERR) ) == true ) { - fprintf( stderr, "%s: Protocol error (%s).\n", PACKAGE, token ); - goto error; - } - else if( STREQ_LEN( token, IMAP4_RSP_FAILURE, strlen(IMAP4_RSP_FAILURE) ) == true ) { - fprintf( stderr, "%s: Failure (%s).\n", PACKAGE, token ); - goto error; + + /* + * We suppose that, if a partial response packet was sent, it is not + * broken in the middle of a line (to confirm). Normally, each string is + * terminated by CRLF. + */ + if (STREQ_LEN(&rx_buffer[len - 2], IMAP4_ENDL, 2) == false) { + /* + * No CRLF found at the end of the buffer --> not handled by + * wmnotify. + */ + ErrorLocation(__FILE__, __LINE__); + fprintf(stderr, + "Response buffer doesn't contain CRLF at the end.\n"); + goto error; } - else { - fprintf( stderr, "%s: Unknown error code (%s).\n", PACKAGE, token ); - goto error; + + if (wmnotify_infos.debug) { + printf("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); + printf("IMAP4 Server Response (size %d bytes):\n", len); + printf("%s", rx_buffer); + printf("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); } - } - else { - fprintf( stderr, "%s: Error, transaction label mismatch.\n", PACKAGE ); - goto error; - } - } - } /* while( token ) */ - - /* Get next part of IMAP4 response. */ - goto get_packet; - - end: - /* No error. */ - return len; - - error: - return -1; + + /* + * Converting the last CRLF into a LF followed by a NULL termination + * character. + */ + rx_buffer[len - 2] = '\n'; + rx_buffer[len - 1] = '\0'; + + /* + * Check the Server Completion Response returned by the IMAP4 server. + * There are currently three Server Completion Responses codes: + * success ("OK") + * failure ("NO") + * protocol error ("BAD") + */ + stringp = rx_buffer; + + while ((token = strsep(&stringp, "\n")) != NULL) { + /* + * In case no delimiter was found, the token is taken to + * be the entire string *stringp, and *stringp is made NULL. + */ + if (stringp == NULL) { + if (token[0] == '\0') { + /* + * This means we finished parsing the last line + * of the buffer, but we need to get more data + * to continue process the next part of the + * IMAP4 response. + */ + goto get_packet; + } else { + /* This should never happen. */ + ErrorLocation(__FILE__, __LINE__); + fprintf(stderr, + " Delimiter not found in strsep() call.\n"); + goto error; + } + } + + if (token == NULL) { + /* This should never happen. */ + ErrorLocation(__FILE__, __LINE__); + fprintf(stderr, + " NULL token returned by strsep().\n"); + goto error; + } + + if (token[0] == '*') { + /* + * Untagged response. If there is a space after the + * SEARCH response, it means at least 1 message is + * unseen. + */ + if (STREQ_LEN + (token, IMAP4_RSP_SEARCH_UNSEEN, + strlen(IMAP4_RSP_SEARCH_UNSEEN)) == true) { + unseen_string_found = true; + } + } else { + /* Must be the status... */ + + /* + * We check for the correct transaction label plus a + * space. + */ + if (STREQ_LEN(token, tx_buffer, tlabel_len + 1) == + true) { + token += tlabel_len + 1; + if (STREQ_LEN + (token, IMAP4_RSP_SUCCESS, + strlen(IMAP4_RSP_SUCCESS)) == true) { + goto end; /* OK, no errors. */ + } else + if (STREQ_LEN + (token, IMAP4_RSP_PROTOCOL_ERR, + strlen(IMAP4_RSP_PROTOCOL_ERR)) == + true) { + fprintf(stderr, + "%s: Protocol error (%s).\n", + PACKAGE, token); + goto error; + } else + if (STREQ_LEN + (token, IMAP4_RSP_FAILURE, + strlen(IMAP4_RSP_FAILURE)) == + true) { + fprintf(stderr, + "%s: Failure (%s).\n", + PACKAGE, token); + goto error; + } else { + fprintf(stderr, + "%s: Unknown error code (%s).\n", + PACKAGE, token); + goto error; + } + } else { + fprintf(stderr, + "%s: Error, transaction label mismatch.\n", + PACKAGE); + goto error; + } + } + } /* while( token ) */ + + /* Get next part of IMAP4 response. */ + goto get_packet; + +end: + /* No error. */ + return len; + +error: + return -1; } -static int -IMAP4_SendCommand( int argc, char *argv[] ) +static int IMAP4_SendCommand(int argc, char *argv[]) { - int len; - int i; - - /* Adding Transaction Label. */ - tlabel++; - tx_buffer[0] = 'A'; - len = 1; - len += sprintf( tx_buffer + len, "%d", tlabel ); - tlabel_len = len; - - /* Adding command and it's arguments. */ - for( i = 0; i < argc; i++ ) { - len += sprintf( tx_buffer + len, " %s", argv[i] ); - } - - if( wmnotify_infos.debug ) { - tx_buffer[len] = '\0'; - printf( ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n" ); - printf( "IMAP4 Client Command (size %d bytes):\n%s\n", len, tx_buffer ); - printf( ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n" ); - } - - /* Adding termination characters. */ - len += sprintf( tx_buffer + len, IMAP4_ENDL ); - - len = WmnotifySendData( tx_buffer, len ); - if( len < 0 ) { - return EXIT_FAILURE; - } - - len = IMAP4_ReceiveResponse(); - if( len < 0 ) { - return EXIT_FAILURE; - } - - return EXIT_SUCCESS; + int len; + int i; + + /* Adding Transaction Label. */ + tlabel++; + tx_buffer[0] = 'A'; + len = 1; + len += sprintf(tx_buffer + len, "%d", tlabel); + tlabel_len = len; + + /* Adding command and it's arguments. */ + for (i = 0; i < argc; i++) + len += sprintf(tx_buffer + len, " %s", argv[i]); + + if (wmnotify_infos.debug) { + tx_buffer[len] = '\0'; + printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); + printf("IMAP4 Client Command (size %d bytes):\n%s\n", len, + tx_buffer); + printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); + } + + /* Adding termination characters. */ + len += sprintf(tx_buffer + len, IMAP4_ENDL); + + len = WmnotifySendData(tx_buffer, len); + if (len < 0) + return EXIT_FAILURE; + + len = IMAP4_ReceiveResponse(); + if (len < 0) + return EXIT_FAILURE; + + return EXIT_SUCCESS; } -int -IMAP4_CheckForNewMail( void ) +int IMAP4_CheckForNewMail(void) { - char *argv[10]; - int new_messages = 0; - int status; - - status = ConnectionEstablish( wmnotify_infos.server_name, wmnotify_infos.port ); - if( status != EXIT_SUCCESS ) { - new_messages = -1; - goto end; - } - - argv[0] = IMAP4_CMD_LOGIN; - argv[1] = wmnotify_infos.username; - argv[2] = wmnotify_infos.password; - status = IMAP4_SendCommand( 3, argv ); - if( status != EXIT_SUCCESS ) { - new_messages = -1; - goto imap4_logout; - } - - /* Selecting the mailbox first. */ - argv[0] = IMAP4_CMD_EXAMINE; - argv[1] = wmnotify_infos.imap_folder; - status = IMAP4_SendCommand( 2, argv ); - if( status != EXIT_SUCCESS ) { - new_messages = -1; - goto imap4_logout; - } - - /* Searching in selected mailbox for new messages. We must use the UNSEEN search criteria - * instead of NEW (combination of RECENT and UNSEEN). If there is a new message, RECENT - * and UNSEEN will have entries. But if we recheck again later, RECENT will report zero. - * RECENT, when set, simply means that there are new messages since our last visit. - But, on the other hand, when using EXAMINE, no messages should lose their RECENT flag. */ - unseen_string_found = false; - argv[0] = IMAP4_CMD_SEARCH_UNSEEN; - argv[1] = ""; - status = IMAP4_SendCommand( 1, argv ); - if( status != EXIT_SUCCESS ) { - new_messages = -1; - goto imap4_logout; - } - - if( unseen_string_found == true ) { - new_messages = 1; - } - - imap4_logout: - argv[0] = IMAP4_CMD_LOGOUT; - status = IMAP4_SendCommand( 1, argv ); - if( status != EXIT_SUCCESS ) { - new_messages = -1; - } - - status = ConnectionTerminate(); - if( status != EXIT_SUCCESS ) { - new_messages = -1; - } - - end: - return new_messages; + char *argv[10]; + int new_messages = 0; + int status; + + status = + ConnectionEstablish(wmnotify_infos.server_name, + wmnotify_infos.port); + if (status != EXIT_SUCCESS) { + new_messages = -1; + goto end; + } + + argv[0] = IMAP4_CMD_LOGIN; + argv[1] = wmnotify_infos.username; + argv[2] = wmnotify_infos.password; + status = IMAP4_SendCommand(3, argv); + if (status != EXIT_SUCCESS) { + new_messages = -1; + goto imap4_logout; + } + + /* Selecting the mailbox first. */ + argv[0] = IMAP4_CMD_EXAMINE; + argv[1] = wmnotify_infos.imap_folder; + status = IMAP4_SendCommand(2, argv); + if (status != EXIT_SUCCESS) { + new_messages = -1; + goto imap4_logout; + } + + /* + * Searching in selected mailbox for new messages. We must use the + * UNSEEN search criteria instead of NEW (combination of RECENT and + * UNSEEN). If there is a new message, RECENT and UNSEEN will have + * entries. But if we recheck again later, RECENT will report zero. + * RECENT, when set, simply means that there are new messages since our + * last visit. But, on the other hand, when using EXAMINE, no messages + * should lose their RECENT flag. + */ + unseen_string_found = false; + argv[0] = IMAP4_CMD_SEARCH_UNSEEN; + argv[1] = ""; + status = IMAP4_SendCommand(1, argv); + if (status != EXIT_SUCCESS) { + new_messages = -1; + goto imap4_logout; + } + + if (unseen_string_found == true) + new_messages = 1; + +imap4_logout: + argv[0] = IMAP4_CMD_LOGOUT; + status = IMAP4_SendCommand(1, argv); + if (status != EXIT_SUCCESS) + new_messages = -1; + + status = ConnectionTerminate(); + if (status != EXIT_SUCCESS) + new_messages = -1; + +end: + return new_messages; }