/****************************************************************************/ /* * imapsocket.c -- Module to check for mail using an IMAP socket * * Functions to logon to an IMAP server and check the user's INBOX for * RECENT or UNSEEN mail. Errors may be logged to ~/.xsession-errors if * stderr is redirected by a call to RedirectErrLog(), otherwise they are * written to stderr. * * It is intended to be used as a set of library functions by a program * that displays and icon, lights a keyboard LED or otherwise notifies * a user that mail is waiting to be read. * * Author: Michael P. Duane mduane@seanet.com * Date: August 12, 1997 * * Copyright (c) 1997-98 by Michael P. Duane * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose and without fee is hereby granted, * provided that the above copyright notice appear in all copies and that * both that copyright notice and this permission notice appear in * supporting documentation. * * This file is provided AS IS with no warranties of any kind. The author * shall have no liability with respect to the infringement of copyrights, * trade secrets or any patents by this file or any part thereof. In no * event will the author be liable for any lost revenue or profits or * other special, indirect and consequential damages. * * Revision History: * ****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #ifndef FALSE #define FALSE 0 #define TRUE ~FALSE #endif #define MAX_BUFFER_SIZE 8192 #define MAX_BUFFER_LINES 32 #define SOCKET_ERROR (-1) char *my_name = ""; int fdImap = (-1); struct sockaddr_in addrImap; int seq_num = 0; char tag [ 8]; char hostname [64] = ""; short port = 0; char user [64] = ""; char passwd [64] = ""; char recv_buf [MAX_BUFFER_SIZE]; char *line [MAX_BUFFER_LINES]; /****************************************************************************/ /* * GetProgramName() * * Extract just the basename from argv[0]. 'basename()' doesn't exist * on all systems. */ char *GetProgramName( char *fullname ) { char *name; return( name = ( (name = strrchr( fullname, '/' )) ? ++name : fullname ) ); } /* GetProgramName */ /****************************************************************************/ /* * RedirectErrLog() * * Redirect stderr to $HOME/.xsesson-errors. Create it if it doesn't * exist, append to it if it does. * */ int RedirectErrLog( void ) { char *home; char xsesserr [255]; int mode = (O_CREAT | O_APPEND | O_WRONLY); int fderr; if ( (home = getenv( "HOME" )) != NULL ) { strcat( strcpy( xsesserr, home ), "/.xsession-errors" ); if ( (fderr = open( xsesserr, mode, 0600 )) > 0 ) { close( STDERR_FILENO ); if ( dup( fderr ) == STDERR_FILENO ) close( fderr ); } return( 0 ); } return( -1 ); }/* RedirectErrLog */ /****************************************************************************/ /* * LogMessage() * * Prepend all error messages with my program name and log the corresponding * errno description string where appropriate. */ void LogMessage( char *msg, int errval ) { if ( errval ) fprintf( stderr, "%s: %s, %s\n", my_name, msg, strerror( errval ) ); else fprintf( stderr, "%s: %s\n", my_name, msg ); } /* LogMessage */ /****************************************************************************/ /* * ParseToken() * * Validate the "token = value" sequence to include a known token and * a valid assignment operator. Store the value in a global on success. */ static void ParseToken( char *token, char *assign, char *value ) { char errmsg [255]; int i; for ( i=0; i< strlen( token ); i++ ) *(token+i) = toupper( *(token+i) ); if ( strcmp( assign, "=" ) ) { sprintf( errmsg, "\"%s\" missing assignment", token ); LogMessage( errmsg, 0 ); return; } if ( !strcmp( token, "HOSTNAME" ) ) strcpy( hostname, value ); else if ( !strcmp( token, "PORT" ) ) port = (short)strtol( value, (char **)NULL, 0 ); else if ( !strcmp( token, "USER" ) ) strcpy( user, value ); else if ( !strcmp( token, "PASSWORD" ) ) strcpy( passwd, value ); else { sprintf( errmsg, "Unexpected configuration token: \"%s\"", token ); LogMessage( errmsg, 0 ); } } /* ParseToken */ /****************************************************************************/ static char *GetNextToken( char *str ) { return( strtok( str, " \t\n\r" ) ); } /* GetNextToken */ /****************************************************************************/ /* * GetImapCfgInfo() * * Reads the program configuration file looking for assignments of the * form "token = value". '#' begins a comment that contiues to EOL. */ int GetImapCfgInfo( char *cfgfile ) { FILE *cfg; char txtbuf [512]; char *txt; char *tok; char *assign; char *val; if ( (cfg = fopen( cfgfile, "r" )) != NULL ) { do { if ( (txt = fgets( txtbuf, sizeof( txtbuf ), cfg )) != NULL) { if ( (tok = GetNextToken( txt )) ) { assign = val = NULL; if ( strlen( tok ) ) { if ( strchr( tok, '#' ) ) continue; assign = GetNextToken( NULL ); val = GetNextToken( NULL ); GetNextToken( NULL ); /* strip to eol */ } if ( assign && val ) ParseToken( tok, assign, val ); } } } while( !feof( cfg ) ); fclose( cfg ); } else { LogMessage( cfgfile, errno ); return( -1 ); } return( 0 ); } /* GetImapCfgInfo */ /****************************************************************************/ /* * InitSocketAddr() * * Setup and validate the host/port address for the IMAP socket */ int InitSocketAddr( void ) { struct hostent *host_info; char addr_str [ 32]; if ( (host_info = gethostbyname( hostname )) == NULL ) { LogMessage( "Host name error", errno ); return( -1 ); } sprintf( addr_str,"%u.%u.%u.%u", (unsigned char)host_info->h_addr_list[0][0], (unsigned char)host_info->h_addr_list[0][1], (unsigned char)host_info->h_addr_list[0][2], (unsigned char)host_info->h_addr_list[0][3] ); addrImap.sin_family = PF_INET; addrImap.sin_addr.s_addr = inet_addr( addr_str ); addrImap.sin_port = htons( port ); if ( addrImap.sin_addr.s_addr == INADDR_NONE ) { LogMessage( "Socket Address Error", errno ); return( -1 ); } return( 0 ); } /* InitSocketAddr */ /****************************************************************************/ /* * ConnectSocket() * * Open and connect to the IMAP socket */ static int ConnectSocket( struct sockaddr_in *addrImap ) { if ( addrImap->sin_addr.s_addr == INADDR_NONE ) { LogMessage( "Socket Address Error", errno ); return( -1 ); } if ( (fdImap = socket( AF_INET, SOCK_STREAM, 0 )) == SOCKET_ERROR ) { LogMessage( "Error opening socket", errno ); return( -1 ); } if ( connect( fdImap, (struct sockaddr *)addrImap, sizeof( struct sockaddr )) == SOCKET_ERROR ) { close( fdImap ); fdImap = (-1); LogMessage( "Socket Connection error", errno ); return( -1 ); } return( 0 ); } /* ConnectSocket */ /****************************************************************************/ /* * OpenImapSocket() * * Connect to the IMAP socket and make sure the IMAP service responds. */ static int OpenImapSocket( struct sockaddr_in *addrImap ) { int i; if ( ConnectSocket( addrImap ) ) return( -1 ); seq_num = 0; memset( recv_buf, 0, sizeof( recv_buf ) ); for( i=0; i 0 ) { for( i=0; i 0 ) { for( i=0; i