/* * wmpop3.c * multi pop3 mail checker. * written by Louis-Benoit JOURDAIN (lb@jourdain.org) * based on the original work by Scott Holden (scotth@thezone.net) * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "Pop3Client.h" #include "wmpop3.xpm" char wminet_mask_bits[64*64]; int wminet_mask_width = 64; int wminet_mask_height = 64; char *ProgName; char mailclient[32] = "pine"; char password[32]; char username[32]; char popserver[128]; int serverport = 110; int mailCheckDelay = 10; /* default */ int autoChecking = YES; /* default */ int newMessagesOnly = YES; /* default */ int displaydelay = 1; char tempdir[1024]; char config_file[256] = "not-defined"; int scrollspeed = 100; Pop3 conf[6]; int nb_conf; /* number of configured pop servers */ int summess; /* total number of messages */ int color; #ifdef _DEBUG int haspassed = 0; #endif t_scrollbar scrollbar; void usage(void); void printversion(void); void wmCheckMail_routine(int, char **); int readConfigFile( char *filename ); void BlitString(char *name, int x, int y, int fragment); void BlitNum(int num, int x, int y, int todelete); int pop3DeleteMail(int num, Pop3 pc); int pop3VerifStats(Pop3 pc); /******************************** * Main Program ********************************/ void deleteoldtmpfiles() { char buf[1024]; DIR *dir; struct dirent *dp; if (tempdir) { if ((dir = opendir(tempdir))) { chdir(tempdir); while((dp = readdir(dir))) { if (!strncmp(dp->d_name, TMPPREFIX, TMPPREFIXLEN)) { sprintf(buf, "%s/%s", tempdir, dp->d_name); #ifdef _DEBUG printf(" delete old tmp file: %s\n", buf); #endif unlink(buf); } } closedir(dir); } } } int main(int argc, char *argv[]) { int i; ProgName = argv[0]; if (strlen(ProgName) >= 5) ProgName += (strlen(ProgName) - 5); for (i=1; i (i+1)) { strcpy(config_file, argv[i+1]); i++; } break; default: usage(); exit(0); break; } } } wmCheckMail_routine(argc, argv); return 0; } void build_line(char *buf, int num, int index, Pop3 pc) { int len; int pos; char tmp[256]; /* display spaces in case alias is less than 3 char long */ memset(tmp, ' ', sizeof(char) * 3); memset(tmp + 3, 0, sizeof(char) * (256 - 3)); memcpy(tmp, pc->alias, strlen(pc->alias)); tmp[3] = ':'; pos = 4; for (len = 0; len < MAIL_BUFLEN && pc->mails[num].from[len]; len++); memcpy(tmp + pos, pc->mails[num].from, len); tmp[pos + len] = '/'; pos += len + 1; for (len = 0; len < MAIL_BUFLEN && pc->mails[num].subject[len]; len++); memcpy(tmp + pos, pc->mails[num].subject, len); len += pos; tmp[len++] = ' '; tmp[len++] = '*'; tmp[len++] = ' '; tmp[len] = '\0'; pos = index % len; if (len - pos < (NB_DISP + EXTRA)) { /* We are at the end of the string */ memcpy(buf, tmp + pos, len - pos); memcpy(buf + len - pos, tmp, (NB_DISP + EXTRA) - len + pos); } else { memcpy(buf, tmp + pos, NB_DISP + EXTRA); } } void display_index(int mail_index, int line, Pop3 pc) { #ifdef _DEBUG if (haspassed) { printf(" mail_index: %d, line: %d, todelete: %d\n", mail_index, line, pc->mails[mail_index].todelete); } #endif if (pc->mails[mail_index].todelete) { copyXPMArea(67, 12, 2, 5, 7, (line * 6) + TOP_MARGIN); } else { copyXPMArea(69, 11, 2, 6, 7, (line * 6) + TOP_MARGIN - 1); } } void ClearDisplay() { int i; copyXPMArea(72, 4, 3, 42, LEFT_MARGIN, 4); copyXPMArea(72, 4, 50, 42, 9, 4 ); for (i = 0; i < NB_LINE; i++) { copyXPMArea(69, 11, 2, 6, 7, (i * 6) + TOP_MARGIN - 1); } } /* return < 0 if error 0 if no pb else nb of mails which couldn't be deleted */ int DeleteMail(Pop3 pc) { int etat = 0; int old_sizeOfAllMessages; int i; old_sizeOfAllMessages = pc->sizeOfAllMessages; BlitString(pc->alias, 10, TOP_MARGIN, 0); BlitString("connect", 10, 6*2 + TOP_MARGIN, 0); RedrawWindow(); etat = pop3MakeConnection(pc, pc->popserver, pc->serverport); if (-1 != etat) { BlitString("login", 10, (6*3) + TOP_MARGIN, 0); RedrawWindow(); etat = pop3Login(pc, pc->username, pc->password); } if (-1 != etat) { BlitString("chk cont", 10, (6*4) + TOP_MARGIN, 0); RedrawWindow(); etat = pop3VerifStats(pc); } if (-1 != etat) { if (etat != old_sizeOfAllMessages) { BlitString("mailbox", 10, TOP_MARGIN, 0); BlitString("content", 10, 6 + TOP_MARGIN, 0); BlitString("changed", 10, 6*2 + TOP_MARGIN, 0); BlitString("between", 10, 6*3 + TOP_MARGIN, 0); BlitString("updates", 10, 6*4 + TOP_MARGIN, 0); BlitString("del can.", 10, 6*6 + TOP_MARGIN, 0); RedrawWindow(); sleep(displaydelay); for (i = 0, etat = 0; i < pc->numOfMessages; i++) { etat += pc->mails[i].todelete; } } else { etat = 0; for (i = 0; i < pc->numOfMessages; i++) { if (pc->mails[i].todelete) { etat += pop3DeleteMail(i + 1, pc); } } } } pop3Quit(pc); return (etat); } /* void launch_mail_client(int iS) { int i; int j; char str[16]; char **args; ClearDisplay(); if ((args = conf[iS]->mailclient)) { BlitString("starting", 10, TOP_MARGIN, 0); for (i = 0; i < 5 && args[i]; i++) { for (j = 0; j < 8 && args[i][j]; j++); memcpy(str, args[i], j); str[j] = '\0'; BlitString(str, 10, (i + 2)*6 + TOP_MARGIN, 0); } if (0 == fork()) { if (execvp(args[0], args)) { perror("execvp"); copyXPMArea(72, 4, 3, 42, LEFT_MARGIN, 4); copyXPMArea(72, 4, 50, 6, 9, 4 ); copyXPMArea(69, 11, 2, 6, 7, TOP_MARGIN - 1); BlitString("Error", 10, TOP_MARGIN, 0); } } else { conf[iS]->nextCheckTime = time(0) + 30; } } else { BlitString(" mail", 10, TOP_MARGIN, 0); BlitString(" client", 10, 6 + TOP_MARGIN, 0); BlitString("not set", 10, 6*2 + TOP_MARGIN, 0); BlitString(" check", 15, 6*5 + TOP_MARGIN, 0); BlitString("wmpop3rc", 10, 6*6 + TOP_MARGIN, 0); } RedrawWindow(); sleep(displaydelay); } */ void display_scrollbar(int index, int totalmessages, int maxlines, int scrollmode) { int delta; int scrollen; int vertpos; if (totalmessages <= maxlines) { #ifdef _DEBUG if (haspassed) printf(" full scrollbar\n"); #endif copyXPMArea((scrollmode) ? 68 : 65, 18, SCROLL_W, SCROLL_H + (2 * SCROLL_EXT), SCROLL_LX, SCROLL_TY); scrollbar.top = SCROLL_TY; scrollbar.bottom = SCROLL_TY + SCROLL_H; scrollbar.allowedspace = SCROLL_H; } else { delta = totalmessages - maxlines; /* determine the size of the scrollbar */ if (0 >= (scrollen = SCROLL_H - ((SCROLL_H / maxlines) * delta))) scrollen = 1; /* determine the position */ scrollbar.allowedspace = SCROLL_H - scrollen; vertpos = scrollbar.allowedspace * index / delta; copyXPMArea((scrollmode) ? 68 : 65, 18, SCROLL_W, SCROLL_EXT, SCROLL_LX, vertpos + SCROLL_TY); copyXPMArea((scrollmode) ? 68 : 65, 18 + SCROLL_EXT, SCROLL_W, scrollen, SCROLL_LX, vertpos + SCROLL_TY + SCROLL_EXT); copyXPMArea((scrollmode) ? 68 : 65, 18 + SCROLL_EXT + SCROLL_H, SCROLL_W, SCROLL_EXT, SCROLL_LX, vertpos + SCROLL_TY + SCROLL_EXT + scrollen); scrollbar.top = vertpos + SCROLL_TY; scrollbar.bottom = vertpos + SCROLL_TY + (SCROLL_EXT * 2) + scrollen; #ifdef _DEBUG if (haspassed) { printf(" index: %d, totalmess:%d, mxli: %d, delta: %d, vertpos: %d, allowedspace: %d, sl:%d\n", index, totalmessages, maxlines, delta, vertpos, scrollbar.allowedspace, scrollen); } #endif } /* RedrawWindow(); */ } int is_for_each_mail(char **command) { int i; if (command) { for (i = 0; command[i]; i++) { if ('%' == command[i][0]) { if (('f' == command[i][1]) || ('s' == command[i][1]) || ('m' == command[i][1]) || ('n' == command[i][1])) return (1); } } } return (0); } char *quotify(char *str) { char *retour; int len; len = strlen(str); if (NULL != (retour = (char *) malloc(sizeof(char) * len + 3))) { retour[0] = '\''; memcpy(retour + 1, str, len); retour[len + 1] = '\''; retour[len + 2] = '\0'; } return (retour); } /* nb: number of the mail on the server - 1 (if -1: for all mails) path: allocated buffer to store path of tmp file newonly: only for new messages onlyselected: only for selected messages pc: main struct. on success return 0 */ int writemailstofile(int nb, char *path, int newonly, int onlyselected, Pop3 pc) { int fd; int len; int i; int retour = 0; int goforwritemail = 0; int mustdisconnect = 0; len = strlen(tempdir); if (len) { path[0] = '\0'; strcat(path, tempdir); if ('/' != tempdir[len - 1]) strcat(path, "/"); strcat(path, TMPPREFIX); strcat(path, "XXXXXX"); #ifdef _DEBUG printf(" creating temporary file [%s]\n", path); printf(" nb=%d, newonly=%d, onlyselected=%d\n", nb, newonly, onlyselected); #endif if (-1 == (fd = mkstemp(path))) { fprintf(stderr, "Error: writing mail to file\n"); perror(path); retour++; } else { /* to prevent connecting many times, do it now. */ if (NOT_CONNECTED == pc->connected) { #ifdef _DEBUG printf(" writemailstofile not connected, connecting\n"); #endif if (pop3MakeConnection(pc,pc->popserver,pc->serverport) == -1){ return (1); } if (pop3Login(pc, pc->username, pc->password) == -1) { return (1); } mustdisconnect = 1; } if (nb < 0) { /* concatenate all the mails into 1 file */ for (i = 0; i < pc->numOfMessages; i++) { goforwritemail = 0; #ifdef _DEBUG printf(" mail %d:", i); #endif if (!newonly && !onlyselected) { #ifdef _DEBUG printf(" !newonly && !onlyselected\n"); #endif goforwritemail = 1; } else if (newonly) { if (pc->mails[i].new && (!onlyselected || (onlyselected && pc->mails[i].todelete))) { #ifdef _DEBUG printf(" newonly\n"); #endif goforwritemail = 1; } } else if (onlyselected && pc->mails[i].todelete) { #ifdef _DEBUG printf(" onlyselected\n"); #endif goforwritemail = 1; } if (goforwritemail) { /* put the mail separator */ if (strlen(pc->mailseparator)) { #ifdef _DEBUG printf(" pc->mailseparator: [%s]\n", pc->mailseparator); #endif write(fd, pc->mailseparator, strlen(pc->mailseparator)); } else { #ifdef _DEBUG printf(" TXT_SEPARATOR: [%s]\n", TXT_SEPARATOR); #endif write(fd, TXT_SEPARATOR, strlen(TXT_SEPARATOR)); } if (pop3WriteOneMail(i + 1, fd, pc)) { retour++; } } } } else { if (pop3WriteOneMail(nb + 1, fd, pc)) retour++; } close(fd); /* close the connection if we've opened it */ if (mustdisconnect) { #ifdef _DEBUG printf(" writemailstofile disconnecting\n"); #endif pop3Quit(pc); } } } else { fprintf(stderr, "no tempdir configured, can't create file\n"); retour++; } return (retour); } /* * do_command_completion * returned array should be freed by calling function * if nbnewmail == 0, for %c option concatenate _all_ the messages */ char **do_command_completion(int num, char **command, int nbnewmail, Pop3 pc) { char **retour; int i; int yaerreur = 0; char path[1024]; for (i = 0; command[i]; i++); #ifdef _DEBUG printf(" %d args to the command, mail num %d\n", i, num); #endif if (NULL == (retour = (char **) malloc (sizeof(char *) * i + 1))) { return (NULL); } memset(retour, 0, sizeof(char *) * i + 1); for (i = 0; command[i]; i++) { #ifdef _DEBUG printf(" arg %d: [%s]\n", i, command[i]); #endif if ('%' == command[i][0]) { switch (command[i][1]) { case 'T': /* total nb of mails */ if (NULL != (retour[i] = (char *) malloc(sizeof(char) * 8))) sprintf(retour[i], "%d", pc->numOfMessages); else yaerreur = 1; break; case 't': /* total nb of new mails */ if (NULL != (retour[i] = (char *) malloc(sizeof(char) * 8))) sprintf(retour[i], "%d", (nbnewmail < 0) ? 0 : 1); else yaerreur = 1; break; case 'C': /* concatenate all the selected mails in 1 file */ if (writemailstofile(-1, path, 0, SELECTONLY, pc)) yaerreur = 1; else if (NULL == (retour[i] = strdup(path))) { yaerreur = 1; } break; case 'c': /* concatenate all the mails in 1 file */ if (writemailstofile(-1, path, (nbnewmail > 0), NOSELECTONLY, pc)) yaerreur = 1; else if (NULL == (retour[i] = strdup(path))) { yaerreur = 1; } break; case 'f': /* from field */ #ifdef _DEBUG printf(" from field: [%s]\n", pc->mails[num].from); #endif if (NULL == (retour[i] = quotify(pc->mails[num].from))) yaerreur = 1; break; case 's': /* subject of the mail */ #ifdef _DEBUG printf(" subject field: [%s]\n", pc->mails[num].subject); #endif if (NULL == (retour[i] = quotify(pc->mails[num].subject))) yaerreur = 1; break; case 'm': /* copy the mail to tmp file */ if (0 <= num) { if (writemailstofile(num, path, (nbnewmail > 0), NOSELECTONLY, pc)) yaerreur = 1; else if (NULL == (retour[i] = strdup(path))) { yaerreur = 1; } } break; case 'n': /* number of the message on the mail server */ if (NULL != (retour[i] = (char *) malloc(sizeof(char) * 8))) sprintf(retour[i], "%d", num + 1); else yaerreur = 1; break; case 'S': /* server name */ if (NULL == (retour[i] = strdup(pc->popserver))) yaerreur = 1; break; case 'a': /* server alias */ if (NULL == (retour[i] = strdup(pc->alias))) yaerreur = 1; break; case 'u': /* user name */ if (NULL == (retour[i] = strdup(pc->username))) yaerreur = 1; break; case 'w': /* user password */ if (NULL == (retour[i] = strdup(pc->password))) yaerreur = 1; break; case 'P': /* server port */ if (NULL != (retour[i] = (char *) malloc(sizeof(char) * 8))) sprintf(retour[i], "%d", pc->serverport); else yaerreur = 1; break; case '%': /* % character, leave in place */ if (NULL == (retour[i] = strdup(command[i]))) yaerreur = 1; break; default: break; } } else { #ifdef _DEBUG printf(" just copying arg [%s]\n", command[i]); #endif if (NULL == (retour[i] = strdup(command[i]))) yaerreur = 1; } } retour[i] = NULL; #ifdef _DEBUG printf(" retour: %ld\n", (long) retour); #endif if (!yaerreur) return (retour); else return (NULL); } /* num is the index of the mail in the mail array if num == -1, means that the command isn't for each mail */ void spawn_command(int num, char **command, int nbnewmail, char *display, Pop3 pc) { char **tmpcommand; char str[16]; int i, j; if (display) { ClearDisplay(); if (!command) { BlitString(display, 10, 6 + TOP_MARGIN, 0); BlitString("not set", 10, 6*2 + TOP_MARGIN, 0); BlitString(" check", 15, 6*5 + TOP_MARGIN, 0); BlitString("wmpop3rc", 10, 6*6 + TOP_MARGIN, 0); } else { BlitString("starting", 10, TOP_MARGIN, 0); for (i = 0; i < 5 && command[i]; i++) { for (j = 0; j < 8 && command[i][j]; j++); memcpy(str, command[i], j); str[j] = '\0'; BlitString(str, 10, (i + 2)*6 + TOP_MARGIN, 0); } RedrawWindow(); } } if (command) { /* check for any '%' sign in the command and complete it */ tmpcommand = do_command_completion(num, command, nbnewmail, pc); if (tmpcommand) { /* launch the command in a new process */ if (0 == fork()) { #ifdef _DEBUG printf(" spawning command: ["); for (i = 0; tmpcommand[i]; i++) { printf(" %s ", tmpcommand[i]); } printf("]\n"); #endif if (execvp(tmpcommand[0], tmpcommand)) { perror("execvp"); } } else { if (display) { /* set the check delay to 30 seconds */ pc->nextCheckTime = time(0) + 30; } /* free the memory (in the parent process...) */ for (i = 0; tmpcommand[i]; i++) { free (tmpcommand[i]); } free (tmpcommand); } } else { if (display) { ClearDisplay(); BlitString(" Error", 15, TOP_MARGIN, 0); BlitString(" While", 15, 6*2 + TOP_MARGIN, 0); BlitString("parsing", 15, 6*3 + TOP_MARGIN, 0); BlitString("command", 15, 6*4 +TOP_MARGIN, 0); BlitString(display, 10, 6*6 + TOP_MARGIN, 0); fprintf(stderr, "Error while parsing %s\n", display); } else fprintf(stderr, "Error while parsing command\n"); } } if (display) { RedrawWindow(); sleep(displaydelay); } } /* * wmCheckMail_routine : This function is used to set up the X display * for wmpop3 and check for mail every n number of minutes. */ void wmCheckMail_routine(int argc, char **argv){ int buttonStatus = -1; int iS; Pop3 pc; int i, j, k; XEvent Event; char str[256]; int index = 0; int fragment = 0; int index_vert = 0; int oldnbmess = 0; int nbsel; int selectedmess; int justreloaded; long thistime; char *linestodel[7]; int unreachable; long sleeplenght; int scrollmode = 0; int nbnewmail; char separ; if( !strcmp( config_file, "not-defined") ) sprintf(config_file, "%s/.wmpop3rc", getenv("HOME")); if( readConfigFile(config_file) == -1){ exit(0); } /* Set up timer for checking mail */ createXBMfromXPM(wminet_mask_bits, wmpop3_xpm , wminet_mask_width, wminet_mask_height); openXwindow(argc, argv, wmpop3_xpm, wminet_mask_bits , wminet_mask_width, wminet_mask_height); AddMouseRegion(0, 19, 49, 30, 58); /* check button */ AddMouseRegion(1, 46, 49, 50, 58 ); /* autocheck button */ AddMouseRegion(2, 53, 49, 57, 58 ); /* switch display button */ AddMouseRegion(3, 5, 49, 16, 58 ); /* delete button */ AddMouseRegion(4, 33, 49, 44, 53); /* top arrow */ AddMouseRegion(5, 33, 54, 44, 58); /* botton arrow */ /* add the mouse regions for each line */ for (i = 0; i < NB_LINE; i++) { AddMouseRegion(6 + i, 9, (i*6) + TOP_MARGIN, 58, (i*6) + TOP_MARGIN + CHAR_HEIGHT); } /* Check if Autochecking is on or off */ if(autoChecking == NO ){ copyXPMArea(142, 38, 7, 11, 45, 48); } else { copyXPMArea(142, 49, 7, 11, 45, 48); } RedrawWindow(); summess = 0; deleteoldtmpfiles(); sleeplenght = (long) 20000L + (20000L - (20000L * scrollspeed / 100)); while (1) { RSET_COLOR; for (iS = 0; iS < nb_conf; iS++) { pc = conf[iS]; if( (((time(0) > pc->nextCheckTime) || (pc->nextCheckTime == 0)) && ( autoChecking == YES)) || (pc->forcedCheck == YES)){ justreloaded = 1; ClearDisplay(); BlitString(pc->alias, 10, TOP_MARGIN, 0); BlitString("connect", 10, (6*2) + TOP_MARGIN, 0); RedrawWindow(); pc->status = 0; if(pop3MakeConnection(pc,pc->popserver,pc->serverport) == -1){ pc->status = 1; } if (!pc->status) { BlitString("login", 10, (6*3) + TOP_MARGIN, 0); RedrawWindow(); if (pop3Login(pc, pc->username, pc->password) == -1 ) pc->status = 2; } if (!pc->status) { BlitString("get mail", 10, (6*4) + TOP_MARGIN, 0); RedrawWindow(); if (pop3CheckMail(pc) == -1) pc->status = 3; } pc->nextCheckTime = time(0) + (pc->mailCheckDelay * SEC_IN_MIN); index = 0; pc->forcedCheck = NO; /* check if new mail has arrived */ for (i = 0, nbnewmail = 0; i < pc->numOfMessages; i++) if (pc->mails[i].new) nbnewmail++; /* launch the new mail command */ if (pc->newmailcommand && (-1 != pc->sizechanged)) { if (nbnewmail) { #ifdef _DEBUG printf(" %d New mail(s) ha(s)(ve) arrived!\n", nbnewmail); #endif if (is_for_each_mail(pc->newmailcommand)) { for (i = 0; i < pc->numOfMessages; i++) if (pc->mails[i].new) spawn_command(i, pc->newmailcommand, nbnewmail, NULL, pc); } else { spawn_command(-1, pc->newmailcommand, nbnewmail, NULL, pc); } } } /* close the connection */ pop3Quit(pc); pc->sizechanged = 0; } } waitpid(0, NULL, WNOHANG); /* reset the number of messages */ unreachable = 1; for (summess = 0, iS = 0; iS < nb_conf; iS++) { pc = conf[iS]; if (!pc->status) { unreachable = 0; summess += pc->numOfMessages; } } /* set the offset from the beginning of the list */ if (summess != oldnbmess) { oldnbmess = summess; if (summess < NB_LINE) index_vert = 0; else { index_vert = summess - NB_LINE; } } memset(str, 0, 128); /* clear the display */ ClearDisplay(); nbsel = 0; for (iS = 0; iS < nb_conf; iS++) { pc = conf[iS]; for (i = 0; i < summess && i < pc->numOfMessages; i++) { #ifdef _DEBUG if (haspassed) { printf(" %s, mails[%d], todelete=%d\n", pc->alias, i, pc->mails[i].todelete); } #endif nbsel += pc->mails[i].todelete; } } if (justreloaded) { /* make sure we display the correct buttons */ justreloaded = 0; if ((NO == newMessagesOnly) && nbsel) copyXPMArea(128,49 ,14 ,11 ,18 ,48 ); else copyXPMArea(128,27 ,14 ,11 ,18 ,48 ); } if (newMessagesOnly == YES ){ /* Show messages waiting */ RSET_COLOR; for (color = 0, iS = 0; iS < nb_conf; iS++) { pc = conf[iS]; if (pc->countunreadonly) separ = '-'; else separ = ':'; switch(pc->status) { case 1: sprintf(str, "%-3s%cC*ER", pc->alias, separ); break; case 2: sprintf(str, "%-3s%cL*ER", pc->alias, separ); break; case 3: sprintf(str, "%-3s%cM*ER", pc->alias, separ); break; default: sprintf(str, "%-3s%c %3d", pc->alias, separ, (pc->countunreadonly) ? pc->numOfUnreadMessages : pc->numOfMessages); break; } BlitString(str, 10, (int) (6*iS) + TOP_MARGIN, 0); SWAP_COLOR; } RSET_COLOR; sprintf(str, "sel.: %2d", nbsel); BlitString(str, 10, (int) (6*6) + TOP_MARGIN, 0); } else { RSET_COLOR; if (0 == summess) { if (unreachable) { BlitString(" error", 10, TOP_MARGIN, 0); } else { BlitString("No Mesg", 10, TOP_MARGIN, 0); } if (autoChecking == YES) { BlitString(" next", 10, 6*2 + TOP_MARGIN, 0); BlitString(" update", 10, 6*3 + TOP_MARGIN, 0); j = SEC_IN_MIN * 1000; thistime = time(0); for (i = 0, k = 0; i < nb_conf; i++) { if ((conf[i]->nextCheckTime - thistime) < j) { j = conf[i]->nextCheckTime - thistime; k = i; } } sprintf(str, " is:%s", conf[k]->alias); BlitString(str, 10, 6*4 + TOP_MARGIN, 0); BlitString(" in", 10, 6*5 + TOP_MARGIN, 0); sprintf(str, "%-5d s.", j); BlitString(str, 10, 6*6 + TOP_MARGIN, 0); } } else { RSET_COLOR; /* iS = index in the conf struct i = index of the mail j = line nb on display */ memset(linestodel, 0, sizeof(char *)); for (iS = 0, j = 0; iS < nb_conf && j < NB_LINE + index_vert; iS++) { pc = conf[iS]; for (i = 0; (j < NB_LINE + index_vert) && i < pc->numOfMessages; j++, i++) { if (j >= index_vert) { build_line(str, i, index, pc); BlitString(str, 10, ((j - index_vert) * 6) + TOP_MARGIN, fragment); display_index(i, (j - index_vert), pc); /* store the address of the delete flag, so that it will */ /* be easier to modify it afterwards */ linestodel[j - index_vert] = &(pc->mails[i].todelete); } } SWAP_COLOR; } display_scrollbar(index_vert, summess, NB_LINE, scrollmode); } fragment++; if (0 == (fragment % (CHAR_WIDTH + 1))) { index++; fragment = 0; /* printf("index=%d, fragment=%d\n", index, fragment); */ } } #ifdef _DEBUG haspassed = 0; #endif RedrawWindow(); RSET_COLOR; /* X Events */ while (XPending(display)){ XNextEvent(display, &Event); switch (Event.type) { case Expose: RedrawWindow(); break; case DestroyNotify: XCloseDisplay(display); exit(0); break; case MotionNotify: if (scrollmode) { #ifdef _DEBUG printf(" ca bouge... index_vert before = %d, %d x %d, allowedspace: %d, summess: %d\n", index_vert, Event.xbutton.x, Event.xbutton.y, scrollbar.allowedspace, summess); #endif if (summess > NB_LINE) { index_vert = scrollbar.orig_index_vert + ((Event.xbutton.y - scrollbar.orig_y) * (summess - NB_LINE) / scrollbar.allowedspace); if (0 > index_vert) index_vert = 0; if (index_vert + NB_LINE > summess) index_vert = summess - NB_LINE; } #ifdef _DEBUG printf(" deplacement de %d pixels --> index_vert = %d\n", Event.xbutton.y - scrollbar.orig_y, index_vert); #endif } break; case ButtonPress: buttonStatus = CheckMouseRegion(Event.xbutton.x, Event.xbutton.y); if (buttonStatus >= 0){ switch (buttonStatus){ case 0 : /* check / open button pressed */ if ((NO == newMessagesOnly) && nbsel) copyXPMArea(128, 60 ,14 ,11 ,18 ,48 ); else copyXPMArea(128,38 ,14 ,11 ,18 ,48 ); break; case 1 : /* autocheck button pressed */ break; case 2: /* switch display button pressed */ break; case 3: /* delete button pressed */ copyXPMArea(127, 15, 14, 11, 4, 48); break; case 4: /* top arrow button pressed */ break; case 5: /* bottom arrow button pressed */ break; default: break; } RedrawWindow(); } else if (SCROLL_LX <= Event.xbutton.x && SCROLL_RX >= Event.xbutton.x && scrollbar.top <= Event.xbutton.y && scrollbar.bottom >= Event.xbutton.y) { scrollbar.orig_y = Event.xbutton.y; scrollbar.orig_index_vert = index_vert; scrollmode = 1; } break; case ButtonRelease: i = CheckMouseRegion(Event.xbutton.x, Event.xbutton.y); if (buttonStatus == i && buttonStatus >= 0){ switch (buttonStatus){ case 0 : /* check button */ if (nbsel && !newMessagesOnly) { copyXPMArea(128,49 ,14 ,11 ,18 ,48 ); /* this is where you launch the open mail command */ for (iS = 0; iS < nb_conf; iS++) { pc = conf[iS]; for (i = 0, selectedmess = 0; i < pc->numOfMessages; i++) { if (pc->mails[i].todelete) { selectedmess = 1; break; } } if (selectedmess) { #ifdef _DEBUG printf(" launching selectedmesgcommand command for conf %d\n", iS); #endif if (is_for_each_mail(pc->selectedmesgcommand)) { #ifdef _DEBUG if (!pc->numOfMessages) { printf(" command is for each mail but there's no mail\n"); } else printf(" command is for each mail\n"); #endif for (i = 0; i < pc->numOfMessages; i++) spawn_command(i, pc->selectedmesgcommand, 0, "selectm.", pc); } else { spawn_command(-1, pc->selectedmesgcommand, 0, "selectm.", pc); } } } } else { copyXPMArea(128,27 ,14 ,11 ,18 ,48 ); for (iS = 0; iS < nb_conf; iS++) conf[iS]->forcedCheck = YES; } break; case 1 : /* autocheck Button */ if (autoChecking == YES){ autoChecking = NO; copyXPMArea(142, 38, 7, 11, 45, 48); } else { autoChecking = YES; for (iS = 0; iS < nb_conf; iS++) conf[iS]->nextCheckTime = time(0) + (conf[iS]->mailCheckDelay * SEC_IN_MIN); copyXPMArea(142, 49, 7, 11, 45, 48); } break; case 2: /* switch display Button */ index = 0; /* change view on # of messages */ if( newMessagesOnly == YES ) { newMessagesOnly = NO; copyXPMArea(149,38 , 7 , 11, 52, 48); if (nbsel) { copyXPMArea(128,49,14,11,18,48); } else { copyXPMArea(128,27,14,11,18,48); } } else { newMessagesOnly = YES; copyXPMArea(149,49 , 7 , 11, 52, 48); copyXPMArea(128,27,14,11,18,48); } #ifdef _DEBUG haspassed = 1; #endif break; case 3: /* delete button */ copyXPMArea(143, 15, 14, 11, 4, 48); j = 0; RSET_COLOR; for (iS = 0; iS < nb_conf; iS++) { pc = conf[iS]; for (i = 0, k = 0; i < pc->numOfMessages; i++) k += pc->mails[i].todelete; if (k) { /* clear the display */ ClearDisplay(); k = DeleteMail(pc); if (k < 0) { sprintf(pc->delstatus, "%-3s: Err", pc->alias); } else if (k > 0) { sprintf(pc->delstatus, "%-3s/D:%2d", pc->alias, k); } else sprintf(pc->delstatus, "%-3s: ok", pc->alias); pc->forcedCheck = YES; } else { sprintf(pc->delstatus, "%-3s:none", pc->alias); } } /* clear the display */ ClearDisplay(); RSET_COLOR; for (iS = 0; iS < nb_conf; iS++) { BlitString(conf[iS]->delstatus, 10, 6*iS + TOP_MARGIN, 0); SWAP_COLOR; } RedrawWindow(); sleep(displaydelay); break; case 4: /* top arrow button pressed */ index_vert--; if (0 > index_vert) index_vert = 0; #ifdef _DEBUG haspassed = 1; #endif break; case 5: /* bottom arrow button pressed */ if (summess > NB_LINE) { index_vert++; if (index_vert + NB_LINE > summess) index_vert = summess - NB_LINE; } #ifdef _DEBUG haspassed = 1; #endif break; default: if (newMessagesOnly == NO) { /* message view mode */ if ((5 < buttonStatus) && (buttonStatus <= 5 + NB_LINE)) { if ((buttonStatus - 6 + index_vert) < summess) { /* first update lines to del */ *(linestodel[buttonStatus - 6]) = 1 - *(linestodel[buttonStatus - 6]); #ifdef _DEBUG printf(" button %d pressed, j'update lines to del\n", buttonStatus - 6); haspassed = 1; #endif nbsel = 0; for (iS = 0; iS < nb_conf; iS++) { pc = conf[iS]; for (i = 0; i < pc->numOfMessages; i++) { nbsel += pc->mails[i].todelete; #ifdef _DEBUG printf(" conf %d, mail %d, todelete = %d\n", iS, i, pc->mails[i].todelete); #endif } } /* display open or reload buttons */ if (nbsel) { copyXPMArea(128,49,14,11,18,48); } else { copyXPMArea(128,27,14,11,18,48); } } } } else { /* summary view mode */ if ((5 < buttonStatus) && (buttonStatus <= 5 + nb_conf)) { if ((Event.xbutton.x > 10) && (Event.xbutton.x < (10 + (4 * (CHAR_WIDTH + 1))))) { #ifdef _DEBUG printf(" launching command for conf %d\n", buttonStatus - 6); #endif pc = conf[buttonStatus - 6]; if (is_for_each_mail(pc->mailclient)) { #ifdef _DEBUG if (!pc->numOfMessages) { printf(" command is for each mail but there's no mail\n"); } #endif for (i = 0; i < pc->numOfMessages; i++) spawn_command(i, pc->mailclient, nbnewmail, "mailcli.", pc); } else { spawn_command(-1, pc->mailclient, nbnewmail, "mailcli.", pc); } } else if ((Event.xbutton.x > (10 + (4 * (CHAR_WIDTH + 1)))) && (Event.xbutton.x < (10 + (8 * (CHAR_WIDTH + 1))))) { /* swap view mode */ conf[buttonStatus - 6]->countunreadonly = 1 - conf[buttonStatus - 6]->countunreadonly; #ifdef _DEBUG printf(" swapping view mode for conf %d: %s\n", buttonStatus - 6, (conf[buttonStatus - 6]->countunreadonly) ? "UnreadMessages" : "TotalMessages"); #endif } } else if ((5 + NB_LINE) == buttonStatus) { /* status summary line pressed */ if ((Event.xbutton.x > 10) && (Event.xbutton.x < (10 + (4 * (CHAR_WIDTH + 1))))) { /* select all messages */ for (iS = 0; iS < nb_conf; iS++) { for (pc = conf[iS], i = 0; i < pc->numOfMessages; i++) { pc->mails[i].todelete = 1; } } } else if ((Event.xbutton.x > (10 + (4 * (CHAR_WIDTH + 1)))) && (Event.xbutton.x < (10 + (8 * (CHAR_WIDTH + 1))))) { /* unselect all messages */ for (iS = 0; iS < nb_conf; iS++) { for (pc = conf[iS], i = 0; i < pc->numOfMessages; i++) { pc->mails[i].todelete = 0; } } } } } break; } } else { if (buttonStatus >= 0) { /* button has been pressed correctly but released somewhere else */ switch(buttonStatus) { case 0: /* check button was pressed */ if ((NO == newMessagesOnly) && nbsel) copyXPMArea(128,49 ,14 ,11 ,18 ,48 ); else copyXPMArea(128,27 ,14 ,11 ,18 ,48 ); break; case 3: /* delete button was pressed */ copyXPMArea(143, 15, 14, 11, 4, 48); break; } } } RedrawWindow(); buttonStatus = -1; scrollmode = 0; break; } } usleep(sleeplenght); } } /* * usage : Prints proper command parameters of wmpop3. */ void usage(void) { fprintf(stdout, "\nWMPop3LB - Louis-Benoit JOURDAIN (wmpop3lb@jourdain.org)\n"); fprintf(stdout, "based on the work by Scott Holden \n\n"); fprintf(stdout, "usage:\n"); fprintf(stdout, " -display \n"); fprintf(stdout, " -geometry +XPOS+YPOS initial window position\n"); fprintf(stdout, " -c use specified config file\n"); fprintf(stdout, " -h this help screen\n"); fprintf(stdout, " -v print the version number\n"); fprintf(stdout, "\n"); } void printversion(void) { fprintf(stdout, "wmpop3 v%s\n", WMPOP3_VERSION); } // Blits a string at given co-ordinates void BlitString(char *name, int x, int y, int fragment) { int i; int c; int k; int row; /* printf("--name: [%s] \n", name); */ for (i = 0, k = x; name[i]; i++) { c = toupper(name[i]); if (c >= 'A' && c <= 'Z') { /* its a letter */ c -= 'A'; row = LETTERS; } else if (c >= '0' && c <= '9') { /* its a number */ c -= '0'; row = NUMBERS; } else switch(c) { case '-': c = 26; row = LETTERS; break; case '*': c = 27; row = LETTERS; break; case ':': c = 10; row = NUMBERS; break; case '/': c = 11; row = NUMBERS; break; case '@': c = 12; row = NUMBERS; break; case '%': c = 15; row = NUMBERS; break; case ' ': c = 13; row = NUMBERS; break; case '.': c = 28; row = LETTERS; break; default: c = 14; row = NUMBERS; break; } /* printf("c:%2d (%c), fragment: %d, i:%d, k=%d ", c, name[i], fragment, i, k); */ if (i > 0 && i < NB_DISP) { copyXPMArea(c * CHAR_WIDTH, CH_COLOR(row), CHAR_WIDTH + 1, CHAR_HEIGHT, k, y); /* printf(" - k1: %d += %d + 1", k, CHAR_WIDTH); */ k += CHAR_WIDTH + 1; } else if (0 == i) { copyXPMArea(c * CHAR_WIDTH + fragment, CH_COLOR(row), CHAR_WIDTH + 1 - fragment, CHAR_HEIGHT, k, y); /* printf(" - k2: %d += %d + 1 - %d", k, CHAR_WIDTH, fragment); */ k += CHAR_WIDTH + 1 - fragment; } else if (fragment && (NB_DISP == i)) { copyXPMArea(c * CHAR_WIDTH, CH_COLOR(row), fragment + 1, CHAR_HEIGHT, k, y); /* printf(" - k3: %d += %d ", k, fragment); */ k += fragment; } /* printf(" -- apres k=%d\n", k); */ } } /* Blits number to given coordinates...*/ void BlitNum(int num, int x, int y, int todelete) { if (todelete) num += 19; copyXPMArea(((num - 1) * (SN_CHAR_W + 1)) + 1, CH_COLOR(SMALL_NUM), SN_CHAR_W, CHAR_HEIGHT + 1, x, y); } int parsestring(char *buf, char *data, int max, FILE *fp) { char *deb; char *end; char *bal; int go = 1; int linelen = 0; /* trim the leading spaces */ memset(data, 0, max); for (deb = buf; *deb && isspace(*deb); deb++); if (!*deb) return (-1); if ('"' == *deb) { ++deb; bal = data; while (go) { #ifdef _DEBUG printf(" line to parse: [%s]\n", deb); #endif /* get to the end of the line */ for (end = deb; *end && ('"' != *end); end++); if (!*end) { /* this is a multiline entry */ linelen += (int) (end - deb); if (linelen > max) { #ifdef _DEBUG printf(" maximum line length reached\n"); #endif return (-1); } memcpy(bal, deb, (int) (end - deb)); bal = data + linelen; if (fgets(buf, CONF_BUFLEN, fp)) { deb = buf; } else { /* end of file reached */ return (-1); } } else { memcpy(bal, deb, end - deb); go = 0; } } } else { for (end = deb; *end && !isspace(*end); end++); memcpy(data, deb, ((end - deb) > max) ? max : end - deb); } #ifdef _DEBUG printf(" parsed string (len=%d) : [%s]\n", strlen(data), data); #endif return (0); } int parsenum(char *buf, int *data) { char *deb; char *end; char temp[32]; memset(temp, 0, 32); for (deb = buf; *deb && isspace(*deb); deb++); if (!*deb) return (-1); if ('"' == *deb) { for (end = ++deb; *end && ('"' != *end); end++); if (!*end) return (-1); memcpy(temp, deb, end - deb); *data = atoi(temp); } else { for (end = deb; *end && !isspace(*end); end++); memcpy(temp, deb, end - deb); *data = atoi(temp); } return (0); } char **build_arg_list(char *buf, int len) { int espaces; int i, j; char **retour; /* count number of args */ for (espaces = 0, i = 0; buf[i] && i < len; i++) if (isspace(buf[i])) espaces++; /* allocate space for the structure */ if (NULL == (retour = (char **) malloc(sizeof(char *) * espaces + 2))) return (NULL); /* get each arg one by one */ for (i = 0, j = 0; j < len && i < 256; i++) { /* get the end of the arg */ for (espaces = j; espaces < len && !isspace(buf[espaces]); espaces++); /* allocate space for the arg */ if (0 == (retour[i] = malloc(sizeof(char) * (espaces - j) + 1))) { /* free what has been allocated */ for (j = 0; j < i; j++) free(retour[j]); return (NULL); } memcpy(retour[i], buf + j, espaces - j); retour[i][espaces - j] = '\0'; j = espaces + 1; } retour[i] = 0; return (retour); } int readConfigFile( char *filename ){ char buf[CONF_BUFLEN]; char tmp[CONF_BUFLEN]; FILE *fp; char *bal; if( (fp = fopen( filename, "r")) == 0 ){ sprintf(config_file, "%s/.wmpop3rc", getenv("HOME")); fprintf(stderr, "-Config file does not exit : %s\n",config_file); fprintf(stderr, "+Trying to create new config file.\n"); if((fp = fopen(config_file,"w")) == 0){ fprintf(stderr, "-Error creating new config file\n"); return -1; } fprintf(fp, "#####################################################\n"); fprintf(fp, "# wmpop3lb configuration file #\n"); fprintf(fp, "# #\n"); fprintf(fp, "# for more information about wmpop3lb, please see: #\n"); fprintf(fp, "# http://wmpop3lb.jourdain.org #\n"); fprintf(fp, "# or send a mail to #\n"); fprintf(fp, "# wmpop3lb@jourdain.org #\n"); fprintf(fp, "#####################################################\n"); fprintf(fp, "autochecking 0 # 1 enables, 0 disables\n"); fprintf(fp, "displaydelay 2 # nb of seconds error info is displayed\n"); fprintf(fp, "scrollspeed 100 # percentage of original scrool speed\n"); fprintf(fp, "tempdir /tmp # directory for tmp files\n"); fprintf(fp, "viewallmessages 0 # 0 Shows the from and subject\n"); fprintf(fp, "# 1 Shows the number of messages\n"); fprintf(fp, "#\n# Replace all values with appropriate data\n#\n"); fprintf(fp, "[Server] # server section\n"); fprintf(fp, "alias \"3 alphanum. char. long alias\"\n"); fprintf(fp, "popserver \" pop3 server name \"\n"); fprintf(fp, "port 110 # default port\n"); fprintf(fp, "username \" pop3 login name \"\n"); fprintf(fp, "password \" pop3 password \"\n"); fprintf(fp, "mailcheckdelay 10 # default mail check time in minutes\n"); fprintf(fp, "countUnreadOnly 0 # count unread messages only\n"); fprintf(fp, "mailclient \"netscape -mail\" # for example...\n"); fprintf(fp, "newmailcommand \" specify new mail command \"\n"); fprintf(fp, "selectedmesgcommand \"specify command for selected mess\"\n"); fprintf(fp, "mailseparator \" separator when concatening messages\"\n"); fprintf(fp, "maxdlsize -1 # (no limit)\n"); fprintf(fp, "#\n# start new [server] section below (up to a total of 6)\n"); fprintf(stderr, "+New config file created : ~/.wmpop3rc\n\n"); fprintf(stderr, "+ ~/.wmpop3rc must be configured before running wmpop3.\n"); fclose(fp); return -1; } nb_conf = 0; tempdir[0] = '\0'; while ((nb_conf < 7) && fgets(buf, CONF_BUFLEN, fp) != 0) { if (buf[0] != '#') { if (!nb_conf && !strncasecmp( buf, "autochecking", 12) ){ if (parsenum(buf + 12, &autoChecking)) fprintf(stderr, "syntax error for parameter autochecking\n"); } else if (!nb_conf && !strncasecmp( buf, "scrollspeed", 11) ){ if (parsenum(buf + 11, &scrollspeed)) fprintf(stderr, "syntax error for parameter scrollspeed\n"); } else if (!nb_conf && !strncasecmp( buf, "displaydelay", 12) ){ if (parsenum(buf + 12, &displaydelay)) fprintf(stderr, "syntax error for parameter displaydelay\n"); } else if (!nb_conf && !strncasecmp(buf, "tempdir", 7)) { if (parsestring(buf + 7, tempdir, 1024, fp)) fprintf(stderr, "syntax error for parameter tempdir\n"); } else if (!strncasecmp(buf, "[server]", 8)) { nb_conf++; if (!(conf[nb_conf - 1] = pop3Create(nb_conf))) { fprintf(stderr, "Can't allocate memory for config structure\n"); fclose(fp); return (-1); } } else if (nb_conf && !strncasecmp(buf, "username", 8) ) { if (parsestring(buf + 8, conf[nb_conf -1]->username, 256, fp)) fprintf(stderr, "section %d: invalid syntax for username\n", nb_conf); } else if (nb_conf && !strncasecmp( buf, "password", 8) ){ if (parsestring(buf + 8, conf[nb_conf - 1]->password, 256, fp)) fprintf(stderr, "section %d: invalid syntax for password\n", nb_conf); } else if (nb_conf && !strncasecmp(buf, "alias", 5) ) { if (parsestring(buf + 5, conf[nb_conf -1]->alias, 3, fp)) fprintf(stderr, "section %d: invalid syntax for alias\n", nb_conf); } else if (nb_conf && !strncasecmp( buf, "popserver", 9) ){ if (parsestring(buf + 9, conf[nb_conf - 1]->popserver, 128, fp)) fprintf(stderr, "section %d: invalid syntax for popserver\n", nb_conf); } else if (nb_conf && !strncasecmp( buf, "port", 4) ){ if (parsenum(buf + 4, &(conf[nb_conf - 1]->serverport))) fprintf(stderr, "section %d: Invalid popserver port number.\n", nb_conf); } else if (!nb_conf && !strncasecmp( buf, "viewallmessages", 15) ){ if (parsenum(buf + 15, &newMessagesOnly)) fprintf(stderr, "section %d: Invalid number ( viewallmessages )\n", nb_conf); } else if (nb_conf && !strncasecmp(buf, "countunreadonly", 15)) { if (parsenum(buf + 15, &(conf[nb_conf - 1]->countunreadonly))) fprintf(stderr, "section %d: Invalid number ( countunreadonly )\n", nb_conf); } else if (nb_conf && !strncasecmp( buf, "mailcheckdelay", 14) ){ if (parsenum(buf + 14, &(conf[nb_conf -1]->mailCheckDelay))) fprintf(stderr, "section %d: Invalid delay time.\n", nb_conf); } else if (nb_conf && !strncasecmp(buf, "mailclient", 10)) { if (parsestring(buf + 10, tmp, 256, fp)) fprintf(stderr, "section %d: Invalid syntax for mailclient.\n", nb_conf); else conf[nb_conf - 1]->mailclient = build_arg_list(tmp, strlen(tmp)); } else if (nb_conf && !strncasecmp(buf, "newmailcommand", 14)) { if (parsestring(buf + 14, tmp, 256, fp)) fprintf(stderr,"section %d: Invalid syntax for newmailcommand.\n", nb_conf); else conf[nb_conf - 1]->newmailcommand = build_arg_list(tmp, strlen(tmp)); } else if (nb_conf && !strncasecmp(buf, "selectedmesgcommand", 19)) { if (parsestring(buf + 19, tmp, 256, fp)) fprintf(stderr, "section %d: Invalid syntax for selectedmesgcommand.\n", nb_conf); else conf[nb_conf - 1]->selectedmesgcommand = build_arg_list(tmp, strlen(tmp)); } else if (nb_conf && !strncasecmp(buf, "mailseparator", 13)) { if (parsestring(buf + 13, conf[nb_conf - 1]->mailseparator, 256, fp)) fprintf(stderr, "section %d: Invalid syntax for mailseparator\n", nb_conf); } else if (nb_conf && !strncasecmp( buf, "maxdlsize", 9) ){ if (parsenum(buf + 9, &(conf[nb_conf -1]->maxdlsize))) fprintf(stderr, "section %d: Invalid maxdlsize.\n", nb_conf); } else if (nb_conf) { if (*buf && (isalpha(*buf) || isalnum(*buf))) fprintf(stderr, "section %d: Unknown indentifier : [%s]\n", nb_conf, buf); } else { for (bal = buf; *bal && !isalnum(*bal); bal++); if (*bal) fprintf(stderr, "identifier outside Server section: [%s]\n", buf); } } } fclose(fp); return 0; }