*
* Copyright (C) 2003 Hugo Villeneuve <hugo@hugovil.com>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ * This file is released under the GPLv2
*/
/* Define filename_M */
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
-#include <ctype.h> /* for isdigit() */
+#include <ctype.h> /* for isdigit() */
#include "common.h"
#include "wmnotify.h"
#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"
#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;
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;
+
+ /*
+ * Converting the last CRLF into a LF followed by a NULL termination
+ * character.
+ */
+ rx_buffer[len - 2] = '\n';
+ rx_buffer[len - 1] = '\0';
+
+ if (wmnotify_infos.debug) {
+ printf("%s", rx_buffer);
}
- }
- 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;
+
+ /*
+ * 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;
+ char debug_buffer[sizeof(tx_buffer)];
+ int debug_len;
+
+ /* Adding Transaction Label. */
+ tlabel++;
+ tx_buffer[0] = 'A';
+ len = 1;
+ len += sprintf(tx_buffer + len, "%d", tlabel);
+ tlabel_len = len;
+
+ debug_len = 0;
+ debug_len += sprintf(debug_buffer + debug_len, "%s", tx_buffer);
+
+ /* Adding command and it's arguments. */
+ for (i = 0; i < argc; i++) {
+ len += sprintf(tx_buffer + len, " %s", argv[i]);
+
+ if (STREQ(argv[0], IMAP4_CMD_LOGIN) && (i == 2)) {
+ debug_len += sprintf(debug_buffer + debug_len,
+ " XXXXXXXX");
+ }
+ else {
+ debug_len += sprintf(debug_buffer + debug_len,
+ " %s", argv[i]);
+ }
+ }
+
+ if (wmnotify_infos.debug) {
+ debug_buffer[debug_len] = '\0';
+ printf("%s\n", debug_buffer);
+ }
+
+ /* 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] = "inbox";
- 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_connection_terminate;
+ }
+
+ /* 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;
+
+imap4_connection_terminate:
+ status = ConnectionTerminate();
+ if (status != EXIT_SUCCESS)
+ new_messages = -1;
+
+end:
+ return new_messages;
}