3 * multi pop3 mail checker.
4 * written by Louis-Benoit JOURDAIN (lb@jourdain.org)
5 * based on the original work by Scott Holden (scotth@thezone.net)
18 #include <sys/socket.h>
20 #include <sys/param.h>
21 #include <sys/types.h>
23 #include <sys/ioctl.h>
27 #include <X11/extensions/shape.h>
31 #include <libdockapp/wmgeneral.h>
32 #include "Pop3Client.h"
36 char wminet_mask_bits
[64*64];
37 int wminet_mask_width
= 64;
38 int wminet_mask_height
= 64;
42 char mailclient
[32] = "pine";
47 int mailCheckDelay
= 10; /* default */
48 int autoChecking
= YES
; /* default */
49 int newMessagesOnly
= YES
; /* default */
52 char config_file
[256] = "not-defined";
53 int scrollspeed
= 100;
56 int nb_conf
; /* number of configured pop servers */
57 int summess
; /* total number of messages */
64 t_scrollbar scrollbar
;
67 void printversion(void);
68 void wmCheckMail_routine(int, char **);
69 int readConfigFile( char *filename
);
71 void BlitString(char *name
, int x
, int y
, int fragment
);
72 void BlitNum(int num
, int x
, int y
, int todelete
);
74 int pop3DeleteMail(int num
, Pop3 pc
);
75 int pop3VerifStats(Pop3 pc
);
77 /********************************
79 ********************************/
80 void deleteoldtmpfiles()
87 if ((dir
= opendir(tempdir
))) {
89 while((dp
= readdir(dir
))) {
90 if (!strncmp(dp
->d_name
, TMPPREFIX
, TMPPREFIXLEN
)) {
91 sprintf(buf
, "%s/%s", tempdir
, dp
->d_name
);
93 printf(" delete old tmp file: %s\n", buf
);
103 int main(int argc
, char *argv
[]) {
108 if (strlen(ProgName
) >= 5)
109 ProgName
+= (strlen(ProgName
) - 5);
111 for (i
=1; i
<argc
; i
++) {
117 if (strcmp(arg
+1, "display")) {
123 if (strcmp(arg
+1, "geometry")) {
135 strcpy(config_file
, argv
[i
+1]);
146 wmCheckMail_routine(argc
, argv
);
151 void build_line(char *buf
, int num
, int index
, Pop3 pc
)
157 /* display spaces in case alias is less than 3 char long */
158 memset(tmp
, ' ', sizeof(char) * 3);
159 memset(tmp
+ 3, 0, sizeof(char) * (256 - 3));
160 memcpy(tmp
, pc
->alias
, strlen(pc
->alias
));
163 for (len
= 0; len
< MAIL_BUFLEN
&& pc
->mails
[num
].from
[len
]; len
++);
164 memcpy(tmp
+ pos
, pc
->mails
[num
].from
, len
);
165 tmp
[pos
+ len
] = '/';
167 for (len
= 0; len
< MAIL_BUFLEN
&& pc
->mails
[num
].subject
[len
]; len
++);
168 memcpy(tmp
+ pos
, pc
->mails
[num
].subject
, len
);
175 if (len
- pos
< (NB_DISP
+ EXTRA
)) { /* We are at the end of the string */
176 memcpy(buf
, tmp
+ pos
, len
- pos
);
177 memcpy(buf
+ len
- pos
, tmp
, (NB_DISP
+ EXTRA
) - len
+ pos
);
180 memcpy(buf
, tmp
+ pos
, NB_DISP
+ EXTRA
);
184 void display_index(int mail_index
, int line
, Pop3 pc
)
188 printf(" mail_index: %d, line: %d, todelete: %d\n",
189 mail_index
, line
, pc
->mails
[mail_index
].todelete
);
192 if (pc
->mails
[mail_index
].todelete
) {
193 copyXPMArea(67, 12, 2, 5, 7, (line
* 6) + TOP_MARGIN
);
196 copyXPMArea(69, 11, 2, 6, 7, (line
* 6) + TOP_MARGIN
- 1);
200 void ClearDisplay() {
203 copyXPMArea(72, 4, 3, 42, LEFT_MARGIN
, 4);
204 copyXPMArea(72, 4, 50, 42, 9, 4 );
205 for (i
= 0; i
< NB_LINE
; i
++) {
206 copyXPMArea(69, 11, 2, 6, 7, (i
* 6) + TOP_MARGIN
- 1);
210 /* return < 0 if error
212 else nb of mails which couldn't be deleted */
213 int DeleteMail(Pop3 pc
)
216 int old_sizeOfAllMessages
;
219 old_sizeOfAllMessages
= pc
->sizeOfAllMessages
;
220 BlitString(pc
->alias
, 10, TOP_MARGIN
, 0);
221 BlitString("connect", 10, 6*2 + TOP_MARGIN
, 0);
223 etat
= pop3MakeConnection(pc
, pc
->popserver
, pc
->serverport
);
225 BlitString("login", 10, (6*3) + TOP_MARGIN
, 0);
227 etat
= pop3Login(pc
, pc
->username
, pc
->password
);
230 BlitString("chk cont", 10, (6*4) + TOP_MARGIN
, 0);
232 etat
= pop3VerifStats(pc
);
235 if (etat
!= old_sizeOfAllMessages
) {
236 BlitString("mailbox", 10, TOP_MARGIN
, 0);
237 BlitString("content", 10, 6 + TOP_MARGIN
, 0);
238 BlitString("changed", 10, 6*2 + TOP_MARGIN
, 0);
239 BlitString("between", 10, 6*3 + TOP_MARGIN
, 0);
240 BlitString("updates", 10, 6*4 + TOP_MARGIN
, 0);
241 BlitString("del can.", 10, 6*6 + TOP_MARGIN
, 0);
244 for (i
= 0, etat
= 0; i
< pc
->numOfMessages
; i
++) {
245 etat
+= pc
->mails
[i
].todelete
;
250 for (i
= 0; i
< pc
->numOfMessages
; i
++) {
251 if (pc
->mails
[i
].todelete
) {
252 etat
+= pop3DeleteMail(i
+ 1, pc
);
262 void launch_mail_client(int iS)
270 if ((args = conf[iS]->mailclient)) {
271 BlitString("starting", 10, TOP_MARGIN, 0);
272 for (i = 0; i < 5 && args[i]; i++) {
273 for (j = 0; j < 8 && args[i][j]; j++);
274 memcpy(str, args[i], j);
276 BlitString(str, 10, (i + 2)*6 + TOP_MARGIN, 0);
279 if (execvp(args[0], args)) {
281 copyXPMArea(72, 4, 3, 42, LEFT_MARGIN, 4);
282 copyXPMArea(72, 4, 50, 6, 9, 4 );
283 copyXPMArea(69, 11, 2, 6, 7, TOP_MARGIN - 1);
284 BlitString("Error", 10, TOP_MARGIN, 0);
288 conf[iS]->nextCheckTime = time(0) + 30;
292 BlitString(" mail", 10, TOP_MARGIN, 0);
293 BlitString(" client", 10, 6 + TOP_MARGIN, 0);
294 BlitString("not set", 10, 6*2 + TOP_MARGIN, 0);
295 BlitString(" check", 15, 6*5 + TOP_MARGIN, 0);
296 BlitString("wmpop3rc", 10, 6*6 + TOP_MARGIN, 0);
303 void display_scrollbar(int index
, int totalmessages
,
304 int maxlines
, int scrollmode
)
310 if (totalmessages
<= maxlines
) {
313 printf(" full scrollbar\n");
315 copyXPMArea((scrollmode
) ? 68 : 65, 18, SCROLL_W
,
316 SCROLL_H
+ (2 * SCROLL_EXT
), SCROLL_LX
, SCROLL_TY
);
317 scrollbar
.top
= SCROLL_TY
;
318 scrollbar
.bottom
= SCROLL_TY
+ SCROLL_H
;
319 scrollbar
.allowedspace
= SCROLL_H
;
322 delta
= totalmessages
- maxlines
;
323 /* determine the size of the scrollbar */
324 if (0 >= (scrollen
= SCROLL_H
- ((SCROLL_H
/ maxlines
) * delta
)))
326 /* determine the position */
327 scrollbar
.allowedspace
= SCROLL_H
- scrollen
;
328 vertpos
= scrollbar
.allowedspace
* index
/ delta
;
329 copyXPMArea((scrollmode
) ? 68 : 65, 18, SCROLL_W
, SCROLL_EXT
,
330 SCROLL_LX
, vertpos
+ SCROLL_TY
);
331 copyXPMArea((scrollmode
) ? 68 : 65, 18 + SCROLL_EXT
, SCROLL_W
, scrollen
,
332 SCROLL_LX
, vertpos
+ SCROLL_TY
+ SCROLL_EXT
);
333 copyXPMArea((scrollmode
) ? 68 : 65, 18 + SCROLL_EXT
+ SCROLL_H
,
334 SCROLL_W
, SCROLL_EXT
,
335 SCROLL_LX
, vertpos
+ SCROLL_TY
+ SCROLL_EXT
+ scrollen
);
336 scrollbar
.top
= vertpos
+ SCROLL_TY
;
337 scrollbar
.bottom
= vertpos
+ SCROLL_TY
+ (SCROLL_EXT
* 2) + scrollen
;
341 printf(" index: %d, totalmess:%d, mxli: %d, delta: %d, vertpos: %d, allowedspace: %d, sl:%d\n",
342 index
, totalmessages
, maxlines
, delta
, vertpos
,
343 scrollbar
.allowedspace
, scrollen
);
347 /* RedrawWindow(); */
350 int is_for_each_mail(char **command
)
355 for (i
= 0; command
[i
]; i
++) {
356 if ('%' == command
[i
][0]) {
357 if (('f' == command
[i
][1]) ||
358 ('s' == command
[i
][1]) ||
359 ('m' == command
[i
][1]) ||
360 ('n' == command
[i
][1]))
368 char *quotify(char *str
)
374 if (NULL
!= (retour
= (char *) malloc(sizeof(char) * len
+ 3))) {
376 memcpy(retour
+ 1, str
, len
);
377 retour
[len
+ 1] = '\'';
378 retour
[len
+ 2] = '\0';
383 /* nb: number of the mail on the server - 1 (if -1: for all mails)
384 path: allocated buffer to store path of tmp file
385 newonly: only for new messages
386 onlyselected: only for selected messages
388 on success return 0 */
389 int writemailstofile(int nb
, char *path
, int newonly
,
390 int onlyselected
, Pop3 pc
)
396 int goforwritemail
= 0;
397 int mustdisconnect
= 0;
399 len
= strlen(tempdir
);
402 strcat(path
, tempdir
);
403 if ('/' != tempdir
[len
- 1])
405 strcat(path
, TMPPREFIX
);
406 strcat(path
, "XXXXXX");
408 printf(" creating temporary file [%s]\n", path
);
409 printf(" nb=%d, newonly=%d, onlyselected=%d\n",
410 nb
, newonly
, onlyselected
);
412 if (-1 == (fd
= mkstemp(path
))) {
413 fprintf(stderr
, "Error: writing mail to file\n");
418 /* to prevent connecting many times, do it now. */
419 if (NOT_CONNECTED
== pc
->connected
) {
421 printf(" writemailstofile not connected, connecting\n");
423 if (pop3MakeConnection(pc
,pc
->popserver
,pc
->serverport
) == -1){
426 if (pop3Login(pc
, pc
->username
, pc
->password
) == -1) {
433 /* concatenate all the mails into 1 file */
434 for (i
= 0; i
< pc
->numOfMessages
; i
++) {
437 printf(" mail %d:", i
);
439 if (!newonly
&& !onlyselected
) {
441 printf(" !newonly && !onlyselected\n");
446 if (pc
->mails
[i
].new &&
447 (!onlyselected
|| (onlyselected
&& pc
->mails
[i
].todelete
))) {
449 printf(" newonly\n");
454 else if (onlyselected
&& pc
->mails
[i
].todelete
) {
456 printf(" onlyselected\n");
460 if (goforwritemail
) {
461 /* put the mail separator */
462 if (strlen(pc
->mailseparator
)) {
464 printf(" pc->mailseparator: [%s]\n", pc
->mailseparator
);
466 write(fd
, pc
->mailseparator
, strlen(pc
->mailseparator
));
470 printf(" TXT_SEPARATOR: [%s]\n", TXT_SEPARATOR
);
472 write(fd
, TXT_SEPARATOR
, strlen(TXT_SEPARATOR
));
474 if (pop3WriteOneMail(i
+ 1, fd
, pc
)) {
482 if (pop3WriteOneMail(nb
+ 1, fd
, pc
))
486 /* close the connection if we've opened it */
487 if (mustdisconnect
) {
489 printf(" writemailstofile disconnecting\n");
496 fprintf(stderr
, "no tempdir configured, can't create file\n");
503 * do_command_completion
504 * returned array should be freed by calling function
505 * if nbnewmail == 0, for %c option concatenate _all_ the messages
507 char **do_command_completion(int num
, char **command
,
508 int nbnewmail
, Pop3 pc
)
515 for (i
= 0; command
[i
]; i
++);
517 printf(" %d args to the command, mail num %d\n", i
, num
);
519 if (NULL
== (retour
= (char **) malloc (sizeof(char *) * i
+ 1))) {
522 memset(retour
, 0, sizeof(char *) * i
+ 1);
523 for (i
= 0; command
[i
]; i
++) {
525 printf(" arg %d: [%s]\n", i
, command
[i
]);
527 if ('%' == command
[i
][0]) {
528 switch (command
[i
][1]) {
529 case 'T': /* total nb of mails */
530 if (NULL
!= (retour
[i
] = (char *) malloc(sizeof(char) * 8)))
531 sprintf(retour
[i
], "%d", pc
->numOfMessages
);
535 case 't': /* total nb of new mails */
536 if (NULL
!= (retour
[i
] = (char *) malloc(sizeof(char) * 8)))
537 sprintf(retour
[i
], "%d", (nbnewmail
< 0) ? 0 : 1);
541 case 'C': /* concatenate all the selected mails in 1 file */
542 if (writemailstofile(-1, path
, 0, SELECTONLY
, pc
))
545 if (NULL
== (retour
[i
] = strdup(path
))) {
549 case 'c': /* concatenate all the mails in 1 file */
550 if (writemailstofile(-1, path
, (nbnewmail
> 0), NOSELECTONLY
, pc
))
553 if (NULL
== (retour
[i
] = strdup(path
))) {
557 case 'f': /* from field */
559 printf(" from field: [%s]\n", pc
->mails
[num
].from
);
561 if (NULL
== (retour
[i
] = quotify(pc
->mails
[num
].from
)))
564 case 's': /* subject of the mail */
566 printf(" subject field: [%s]\n", pc
->mails
[num
].subject
);
568 if (NULL
== (retour
[i
] = quotify(pc
->mails
[num
].subject
)))
571 case 'm': /* copy the mail to tmp file */
573 if (writemailstofile(num
, path
, (nbnewmail
> 0), NOSELECTONLY
, pc
))
576 if (NULL
== (retour
[i
] = strdup(path
))) {
581 case 'n': /* number of the message on the mail server */
582 if (NULL
!= (retour
[i
] = (char *) malloc(sizeof(char) * 8)))
583 sprintf(retour
[i
], "%d", num
+ 1);
587 case 'S': /* server name */
588 if (NULL
== (retour
[i
] = strdup(pc
->popserver
)))
591 case 'a': /* server alias */
592 if (NULL
== (retour
[i
] = strdup(pc
->alias
)))
595 case 'u': /* user name */
596 if (NULL
== (retour
[i
] = strdup(pc
->username
)))
599 case 'w': /* user password */
600 if (NULL
== (retour
[i
] = strdup(pc
->password
)))
603 case 'P': /* server port */
604 if (NULL
!= (retour
[i
] = (char *) malloc(sizeof(char) * 8)))
605 sprintf(retour
[i
], "%d", pc
->serverport
);
609 case '%': /* % character, leave in place */
610 if (NULL
== (retour
[i
] = strdup(command
[i
])))
619 printf(" just copying arg [%s]\n", command
[i
]);
621 if (NULL
== (retour
[i
] = strdup(command
[i
])))
627 printf(" retour: %ld\n", (long) retour
);
635 /* num is the index of the mail in the mail array
636 if num == -1, means that the command isn't for each mail */
639 void spawn_command(int num
, char **command
, int nbnewmail
,
640 char *display
, Pop3 pc
)
649 BlitString(display
, 10, 6 + TOP_MARGIN
, 0);
650 BlitString("not set", 10, 6*2 + TOP_MARGIN
, 0);
651 BlitString(" check", 15, 6*5 + TOP_MARGIN
, 0);
652 BlitString("wmpop3rc", 10, 6*6 + TOP_MARGIN
, 0);
655 BlitString("starting", 10, TOP_MARGIN
, 0);
656 for (i
= 0; i
< 5 && command
[i
]; i
++) {
657 for (j
= 0; j
< 8 && command
[i
][j
]; j
++);
658 memcpy(str
, command
[i
], j
);
660 BlitString(str
, 10, (i
+ 2)*6 + TOP_MARGIN
, 0);
666 /* check for any '%' sign in the command and complete it */
667 tmpcommand
= do_command_completion(num
, command
, nbnewmail
, pc
);
669 /* launch the command in a new process */
672 printf(" spawning command: [");
673 for (i
= 0; tmpcommand
[i
]; i
++) {
674 printf(" %s ", tmpcommand
[i
]);
678 if (execvp(tmpcommand
[0], tmpcommand
)) {
684 /* set the check delay to 30 seconds */
685 pc
->nextCheckTime
= time(0) + 30;
687 /* free the memory (in the parent process...) */
688 for (i
= 0; tmpcommand
[i
]; i
++) {
689 free (tmpcommand
[i
]);
697 BlitString(" Error", 15, TOP_MARGIN
, 0);
698 BlitString(" While", 15, 6*2 + TOP_MARGIN
, 0);
699 BlitString("parsing", 15, 6*3 + TOP_MARGIN
, 0);
700 BlitString("command", 15, 6*4 +TOP_MARGIN
, 0);
701 BlitString(display
, 10, 6*6 + TOP_MARGIN
, 0);
702 fprintf(stderr
, "Error while parsing %s\n", display
);
705 fprintf(stderr
, "Error while parsing command\n");
715 * wmCheckMail_routine : This function is used to set up the X display
716 * for wmpop3 and check for mail every n number of minutes.
719 void wmCheckMail_routine(int argc
, char **argv
){
721 int buttonStatus
= -1;
742 if( !strcmp( config_file
, "not-defined") )
743 sprintf(config_file
, "%s/.wmpop3rc", getenv("HOME"));
745 if( readConfigFile(config_file
) == -1){
748 /* Set up timer for checking mail */
749 createXBMfromXPM(wminet_mask_bits
, wmpop3_xpm
750 , wminet_mask_width
, wminet_mask_height
);
752 openXwindow(argc
, argv
, wmpop3_xpm
, wminet_mask_bits
753 , wminet_mask_width
, wminet_mask_height
);
755 AddMouseRegion(0, 19, 49, 30, 58); /* check button */
756 AddMouseRegion(1, 46, 49, 50, 58 ); /* autocheck button */
757 AddMouseRegion(2, 53, 49, 57, 58 ); /* switch display button */
758 AddMouseRegion(3, 5, 49, 16, 58 ); /* delete button */
759 AddMouseRegion(4, 33, 49, 44, 53); /* top arrow */
760 AddMouseRegion(5, 33, 54, 44, 58); /* botton arrow */
761 /* add the mouse regions for each line */
762 for (i
= 0; i
< NB_LINE
; i
++) {
763 AddMouseRegion(6 + i
, 9, (i
*6) + TOP_MARGIN
,
764 58, (i
*6) + TOP_MARGIN
+ CHAR_HEIGHT
);
768 /* Check if Autochecking is on or off */
769 if(autoChecking
== NO
){
770 copyXPMArea(142, 38, 7, 11, 45, 48);
773 copyXPMArea(142, 49, 7, 11, 45, 48);
782 sleeplenght
= (long) 20000L + (20000L - (20000L * scrollspeed
/ 100));
785 for (iS
= 0; iS
< nb_conf
; iS
++) {
787 if( (((time(0) > pc
->nextCheckTime
) ||
788 (pc
->nextCheckTime
== 0)) && ( autoChecking
== YES
))
789 || (pc
->forcedCheck
== YES
)){
792 BlitString(pc
->alias
, 10, TOP_MARGIN
, 0);
793 BlitString("connect", 10, (6*2) + TOP_MARGIN
, 0);
796 if(pop3MakeConnection(pc
,pc
->popserver
,pc
->serverport
) == -1){
800 BlitString("login", 10, (6*3) + TOP_MARGIN
, 0);
802 if (pop3Login(pc
, pc
->username
, pc
->password
) == -1 )
806 BlitString("get mail", 10, (6*4) + TOP_MARGIN
, 0);
808 if (pop3CheckMail(pc
) == -1)
811 pc
->nextCheckTime
= time(0) + (pc
->mailCheckDelay
* SEC_IN_MIN
);
813 pc
->forcedCheck
= NO
;
814 /* check if new mail has arrived */
815 for (i
= 0, nbnewmail
= 0; i
< pc
->numOfMessages
; i
++)
816 if (pc
->mails
[i
].new)
818 /* launch the new mail command */
819 if (pc
->newmailcommand
&& (-1 != pc
->sizechanged
)) {
822 printf(" %d New mail(s) ha(s)(ve) arrived!\n", nbnewmail
);
824 if (is_for_each_mail(pc
->newmailcommand
)) {
825 for (i
= 0; i
< pc
->numOfMessages
; i
++)
826 if (pc
->mails
[i
].new)
827 spawn_command(i
, pc
->newmailcommand
, nbnewmail
, NULL
, pc
);
830 spawn_command(-1, pc
->newmailcommand
, nbnewmail
, NULL
, pc
);
834 /* close the connection */
839 waitpid(0, NULL
, WNOHANG
);
840 /* reset the number of messages */
842 for (summess
= 0, iS
= 0; iS
< nb_conf
; iS
++) {
846 summess
+= pc
->numOfMessages
;
849 /* set the offset from the beginning of the list */
850 if (summess
!= oldnbmess
) {
852 if (summess
< NB_LINE
)
855 index_vert
= summess
- NB_LINE
;
859 /* clear the display */
862 for (iS
= 0; iS
< nb_conf
; iS
++) {
864 for (i
= 0; i
< summess
&& i
< pc
->numOfMessages
; i
++) {
867 printf(" %s, mails[%d], todelete=%d\n",
868 pc
->alias
, i
, pc
->mails
[i
].todelete
);
871 nbsel
+= pc
->mails
[i
].todelete
;
875 /* make sure we display the correct buttons */
877 if ((NO
== newMessagesOnly
) && nbsel
)
878 copyXPMArea(128,49 ,14 ,11 ,18 ,48 );
880 copyXPMArea(128,27 ,14 ,11 ,18 ,48 );
882 if (newMessagesOnly
== YES
){
883 /* Show messages waiting */
885 for (color
= 0, iS
= 0; iS
< nb_conf
; iS
++) {
887 if (pc
->countunreadonly
)
893 sprintf(str
, "%-3s%cC*ER", pc
->alias
, separ
);
896 sprintf(str
, "%-3s%cL*ER", pc
->alias
, separ
);
899 sprintf(str
, "%-3s%cM*ER", pc
->alias
, separ
);
902 sprintf(str
, "%-3s%c %3d", pc
->alias
, separ
,
903 (pc
->countunreadonly
) ? pc
->numOfUnreadMessages
:
907 BlitString(str
, 10, (int) (6*iS
) + TOP_MARGIN
, 0);
911 sprintf(str
, "sel.: %2d", nbsel
);
912 BlitString(str
, 10, (int) (6*6) + TOP_MARGIN
, 0);
918 BlitString(" error", 10, TOP_MARGIN
, 0);
921 BlitString("No Mesg", 10, TOP_MARGIN
, 0);
923 if (autoChecking
== YES
) {
924 BlitString(" next", 10, 6*2 + TOP_MARGIN
, 0);
925 BlitString(" update", 10, 6*3 + TOP_MARGIN
, 0);
926 j
= SEC_IN_MIN
* 1000;
928 for (i
= 0, k
= 0; i
< nb_conf
; i
++) {
929 if ((conf
[i
]->nextCheckTime
- thistime
) < j
) {
930 j
= conf
[i
]->nextCheckTime
- thistime
;
934 sprintf(str
, " is:%s", conf
[k
]->alias
);
935 BlitString(str
, 10, 6*4 + TOP_MARGIN
, 0);
936 BlitString(" in", 10, 6*5 + TOP_MARGIN
, 0);
937 sprintf(str
, "%-5d s.", j
);
938 BlitString(str
, 10, 6*6 + TOP_MARGIN
, 0);
943 /* iS = index in the conf struct
944 i = index of the mail
945 j = line nb on display */
946 memset(linestodel
, 0, sizeof(char *));
947 for (iS
= 0, j
= 0; iS
< nb_conf
&& j
< NB_LINE
+ index_vert
; iS
++) {
949 for (i
= 0; (j
< NB_LINE
+ index_vert
) && i
< pc
->numOfMessages
;
951 if (j
>= index_vert
) {
952 build_line(str
, i
, index
, pc
);
953 BlitString(str
, 10, ((j
- index_vert
) * 6) + TOP_MARGIN
,
955 display_index(i
, (j
- index_vert
), pc
);
956 /* store the address of the delete flag, so that it will */
957 /* be easier to modify it afterwards */
958 linestodel
[j
- index_vert
] = &(pc
->mails
[i
].todelete
);
963 display_scrollbar(index_vert
, summess
, NB_LINE
, scrollmode
);
966 if (0 == (fragment
% (CHAR_WIDTH
+ 1))) {
969 /* printf("index=%d, fragment=%d\n", index, fragment); */
980 while (XPending(display
)){
981 XNextEvent(display
, &Event
);
982 switch (Event
.type
) {
987 XCloseDisplay(display
);
993 printf(" ca bouge... index_vert before = %d, %d x %d, allowedspace: %d, summess: %d\n",
995 Event
.xbutton
.x
, Event
.xbutton
.y
,
996 scrollbar
.allowedspace
,
1000 if (summess
> NB_LINE
) {
1001 index_vert
= scrollbar
.orig_index_vert
+
1002 ((Event
.xbutton
.y
- scrollbar
.orig_y
) * (summess
- NB_LINE
) /
1003 scrollbar
.allowedspace
);
1006 if (index_vert
+ NB_LINE
> summess
)
1007 index_vert
= summess
- NB_LINE
;
1010 printf(" deplacement de %d pixels --> index_vert = %d\n",
1011 Event
.xbutton
.y
- scrollbar
.orig_y
, index_vert
);
1016 buttonStatus
= CheckMouseRegion(Event
.xbutton
.x
, Event
.xbutton
.y
);
1017 if (buttonStatus
>= 0){
1018 switch (buttonStatus
){
1019 case 0 : /* check / open button pressed */
1020 if ((NO
== newMessagesOnly
) && nbsel
)
1021 copyXPMArea(128, 60 ,14 ,11 ,18 ,48 );
1023 copyXPMArea(128,38 ,14 ,11 ,18 ,48 );
1025 case 1 : /* autocheck button pressed */
1027 case 2: /* switch display button pressed */
1029 case 3: /* delete button pressed */
1030 copyXPMArea(127, 15, 14, 11, 4, 48);
1032 case 4: /* top arrow button pressed */
1034 case 5: /* bottom arrow button pressed */
1041 else if (SCROLL_LX
<= Event
.xbutton
.x
&& SCROLL_RX
>= Event
.xbutton
.x
1042 && scrollbar
.top
<= Event
.xbutton
.y
&&
1043 scrollbar
.bottom
>= Event
.xbutton
.y
) {
1044 scrollbar
.orig_y
= Event
.xbutton
.y
;
1045 scrollbar
.orig_index_vert
= index_vert
;
1050 i
= CheckMouseRegion(Event
.xbutton
.x
, Event
.xbutton
.y
);
1052 if (buttonStatus
== i
&& buttonStatus
>= 0){
1053 switch (buttonStatus
){
1054 case 0 : /* check button */
1055 if (nbsel
&& !newMessagesOnly
) {
1056 copyXPMArea(128,49 ,14 ,11 ,18 ,48 );
1057 /* this is where you launch the open mail command */
1058 for (iS
= 0; iS
< nb_conf
; iS
++) {
1060 for (i
= 0, selectedmess
= 0; i
< pc
->numOfMessages
; i
++) {
1061 if (pc
->mails
[i
].todelete
) {
1068 printf(" launching selectedmesgcommand command for conf %d\n",
1072 if (is_for_each_mail(pc
->selectedmesgcommand
)) {
1074 if (!pc
->numOfMessages
) {
1075 printf(" command is for each mail but there's no mail\n");
1078 printf(" command is for each mail\n");
1080 for (i
= 0; i
< pc
->numOfMessages
; i
++)
1081 spawn_command(i
, pc
->selectedmesgcommand
, 0,
1085 spawn_command(-1, pc
->selectedmesgcommand
, 0,
1092 copyXPMArea(128,27 ,14 ,11 ,18 ,48 );
1093 for (iS
= 0; iS
< nb_conf
; iS
++)
1094 conf
[iS
]->forcedCheck
= YES
;
1097 case 1 : /* autocheck Button */
1098 if (autoChecking
== YES
){
1100 copyXPMArea(142, 38, 7, 11, 45, 48);
1104 for (iS
= 0; iS
< nb_conf
; iS
++)
1105 conf
[iS
]->nextCheckTime
= time(0) +
1106 (conf
[iS
]->mailCheckDelay
* SEC_IN_MIN
);
1107 copyXPMArea(142, 49, 7, 11, 45, 48);
1110 case 2: /* switch display Button */
1112 /* change view on # of messages */
1113 if( newMessagesOnly
== YES
) {
1114 newMessagesOnly
= NO
;
1115 copyXPMArea(149,38 , 7 , 11, 52, 48);
1117 copyXPMArea(128,49,14,11,18,48);
1120 copyXPMArea(128,27,14,11,18,48);
1124 newMessagesOnly
= YES
;
1125 copyXPMArea(149,49 , 7 , 11, 52, 48);
1126 copyXPMArea(128,27,14,11,18,48);
1132 case 3: /* delete button */
1133 copyXPMArea(143, 15, 14, 11, 4, 48);
1136 for (iS
= 0; iS
< nb_conf
; iS
++) {
1138 for (i
= 0, k
= 0; i
< pc
->numOfMessages
; i
++)
1139 k
+= pc
->mails
[i
].todelete
;
1141 /* clear the display */
1145 sprintf(pc
->delstatus
, "%-3s: Err", pc
->alias
);
1148 sprintf(pc
->delstatus
, "%-3s/D:%2d", pc
->alias
, k
);
1151 sprintf(pc
->delstatus
, "%-3s: ok", pc
->alias
);
1152 pc
->forcedCheck
= YES
;
1155 sprintf(pc
->delstatus
, "%-3s:none", pc
->alias
);
1158 /* clear the display */
1161 for (iS
= 0; iS
< nb_conf
; iS
++) {
1162 BlitString(conf
[iS
]->delstatus
, 10, 6*iS
+ TOP_MARGIN
, 0);
1166 sleep(displaydelay
);
1168 case 4: /* top arrow button pressed */
1176 case 5: /* bottom arrow button pressed */
1177 if (summess
> NB_LINE
) {
1179 if (index_vert
+ NB_LINE
> summess
)
1180 index_vert
= summess
- NB_LINE
;
1187 if (newMessagesOnly
== NO
) { /* message view mode */
1188 if ((5 < buttonStatus
) && (buttonStatus
<= 5 + NB_LINE
)) {
1189 if ((buttonStatus
- 6 + index_vert
) < summess
) {
1190 /* first update lines to del */
1191 *(linestodel
[buttonStatus
- 6]) =
1192 1 - *(linestodel
[buttonStatus
- 6]);
1194 printf(" button %d pressed, j'update lines to del\n",
1199 for (iS
= 0; iS
< nb_conf
; iS
++) {
1201 for (i
= 0; i
< pc
->numOfMessages
; i
++) {
1202 nbsel
+= pc
->mails
[i
].todelete
;
1204 printf(" conf %d, mail %d, todelete = %d\n",
1205 iS
, i
, pc
->mails
[i
].todelete
);
1209 /* display open or reload buttons */
1211 copyXPMArea(128,49,14,11,18,48);
1214 copyXPMArea(128,27,14,11,18,48);
1219 else { /* summary view mode */
1220 if ((5 < buttonStatus
) && (buttonStatus
<= 5 + nb_conf
)) {
1221 if ((Event
.xbutton
.x
> 10) &&
1222 (Event
.xbutton
.x
< (10 + (4 * (CHAR_WIDTH
+ 1))))) {
1224 printf(" launching command for conf %d\n",
1227 pc
= conf
[buttonStatus
- 6];
1228 if (is_for_each_mail(pc
->mailclient
)) {
1230 if (!pc
->numOfMessages
) {
1231 printf(" command is for each mail but there's no mail\n");
1234 for (i
= 0; i
< pc
->numOfMessages
; i
++)
1235 spawn_command(i
, pc
->mailclient
, nbnewmail
,
1239 spawn_command(-1, pc
->mailclient
, nbnewmail
,
1243 else if ((Event
.xbutton
.x
> (10 + (4 * (CHAR_WIDTH
+ 1)))) &&
1244 (Event
.xbutton
.x
< (10 + (8 * (CHAR_WIDTH
+ 1))))) {
1245 /* swap view mode */
1246 conf
[buttonStatus
- 6]->countunreadonly
=
1247 1 - conf
[buttonStatus
- 6]->countunreadonly
;
1249 printf(" swapping view mode for conf %d: %s\n",
1251 (conf
[buttonStatus
- 6]->countunreadonly
) ?
1252 "UnreadMessages" : "TotalMessages");
1257 else if ((5 + NB_LINE
) == buttonStatus
) {
1258 /* status summary line pressed */
1259 if ((Event
.xbutton
.x
> 10) &&
1260 (Event
.xbutton
.x
< (10 + (4 * (CHAR_WIDTH
+ 1))))) {
1261 /* select all messages */
1262 for (iS
= 0; iS
< nb_conf
; iS
++) {
1263 for (pc
= conf
[iS
], i
= 0; i
< pc
->numOfMessages
; i
++) {
1264 pc
->mails
[i
].todelete
= 1;
1268 else if ((Event
.xbutton
.x
> (10 + (4 * (CHAR_WIDTH
+ 1)))) &&
1269 (Event
.xbutton
.x
< (10 + (8 * (CHAR_WIDTH
+ 1))))) {
1270 /* unselect all messages */
1271 for (iS
= 0; iS
< nb_conf
; iS
++) {
1272 for (pc
= conf
[iS
], i
= 0; i
< pc
->numOfMessages
; i
++) {
1273 pc
->mails
[i
].todelete
= 0;
1283 if (buttonStatus
>= 0) {
1284 /* button has been pressed correctly but released somewhere else */
1285 switch(buttonStatus
) {
1286 case 0: /* check button was pressed */
1287 if ((NO
== newMessagesOnly
) && nbsel
)
1288 copyXPMArea(128,49 ,14 ,11 ,18 ,48 );
1290 copyXPMArea(128,27 ,14 ,11 ,18 ,48 );
1292 case 3: /* delete button was pressed */
1293 copyXPMArea(143, 15, 14, 11, 4, 48);
1304 usleep(sleeplenght
);
1310 * usage : Prints proper command parameters of wmpop3.
1314 fprintf(stdout
, "\nWMPop3LB - Louis-Benoit JOURDAIN (wmpop3lb@jourdain.org)\n");
1315 fprintf(stdout
, "based on the work by Scott Holden <scotth@thezone.net>\n\n");
1316 fprintf(stdout
, "usage:\n");
1317 fprintf(stdout
, " -display <display name>\n");
1318 fprintf(stdout
, " -geometry +XPOS+YPOS initial window position\n");
1319 fprintf(stdout
, " -c <filename> use specified config file\n");
1320 fprintf(stdout
, " -h this help screen\n");
1321 fprintf(stdout
, " -v print the version number\n");
1322 fprintf(stdout
, "\n");
1325 void printversion(void)
1327 fprintf(stdout
, "wmpop3 v%s\n", WMPOP3_VERSION
);
1330 // Blits a string at given co-ordinates
1331 void BlitString(char *name
, int x
, int y
, int fragment
)
1338 /* printf("--name: [%s] \n", name); */
1339 for (i
= 0, k
= x
; name
[i
]; i
++) {
1340 c
= toupper(name
[i
]);
1341 if (c
>= 'A' && c
<= 'Z') { /* its a letter */
1345 else if (c
>= '0' && c
<= '9') { /* its a number */
1387 /* printf("c:%2d (%c), fragment: %d, i:%d, k=%d ",
1388 c, name[i], fragment, i, k); */
1389 if (i
> 0 && i
< NB_DISP
) {
1390 copyXPMArea(c
* CHAR_WIDTH
, CH_COLOR(row
), CHAR_WIDTH
+ 1, CHAR_HEIGHT
,
1392 /* printf(" - k1: %d += %d + 1", k, CHAR_WIDTH); */
1393 k
+= CHAR_WIDTH
+ 1;
1396 copyXPMArea(c
* CHAR_WIDTH
+ fragment
, CH_COLOR(row
),
1397 CHAR_WIDTH
+ 1 - fragment
, CHAR_HEIGHT
,
1399 /* printf(" - k2: %d += %d + 1 - %d", k, CHAR_WIDTH, fragment); */
1400 k
+= CHAR_WIDTH
+ 1 - fragment
;
1402 else if (fragment
&& (NB_DISP
== i
)) {
1403 copyXPMArea(c
* CHAR_WIDTH
, CH_COLOR(row
), fragment
+ 1, CHAR_HEIGHT
,
1405 /* printf(" - k3: %d += %d ", k, fragment); */
1408 /* printf(" -- apres k=%d\n", k); */
1413 /* Blits number to given coordinates...*/
1415 void BlitNum(int num
, int x
, int y
, int todelete
)
1419 copyXPMArea(((num
- 1) * (SN_CHAR_W
+ 1)) + 1, CH_COLOR(SMALL_NUM
),
1420 SN_CHAR_W
, CHAR_HEIGHT
+ 1, x
, y
);
1423 int parsestring(char *buf
, char *data
, int max
, FILE *fp
)
1431 /* trim the leading spaces */
1432 memset(data
, 0, max
);
1433 for (deb
= buf
; *deb
&& isspace(*deb
); deb
++);
1441 printf(" line to parse: [%s]\n", deb
);
1443 /* get to the end of the line */
1444 for (end
= deb
; *end
&& ('"' != *end
); end
++);
1445 if (!*end
) { /* this is a multiline entry */
1446 linelen
+= (int) (end
- deb
);
1447 if (linelen
> max
) {
1449 printf(" maximum line length reached\n");
1453 memcpy(bal
, deb
, (int) (end
- deb
));
1454 bal
= data
+ linelen
;
1455 if (fgets(buf
, CONF_BUFLEN
, fp
)) {
1458 else { /* end of file reached */
1463 memcpy(bal
, deb
, end
- deb
);
1469 for (end
= deb
; *end
&& !isspace(*end
); end
++);
1470 memcpy(data
, deb
, ((end
- deb
) > max
) ? max
: end
- deb
);
1473 printf(" parsed string (len=%d) : [%s]\n", strlen(data
), data
);
1478 int parsenum(char *buf
, int *data
)
1484 memset(temp
, 0, 32);
1485 for (deb
= buf
; *deb
&& isspace(*deb
); deb
++);
1489 for (end
= ++deb
; *end
&& ('"' != *end
); end
++);
1492 memcpy(temp
, deb
, end
- deb
);
1496 for (end
= deb
; *end
&& !isspace(*end
); end
++);
1497 memcpy(temp
, deb
, end
- deb
);
1503 char **build_arg_list(char *buf
, int len
)
1509 /* count number of args */
1510 for (espaces
= 0, i
= 0; buf
[i
] && i
< len
; i
++)
1511 if (isspace(buf
[i
]))
1513 /* allocate space for the structure */
1514 if (NULL
== (retour
= (char **) malloc(sizeof(char *) * espaces
+ 2)))
1516 /* get each arg one by one */
1517 for (i
= 0, j
= 0; j
< len
&& i
< 256; i
++) {
1518 /* get the end of the arg */
1519 for (espaces
= j
; espaces
< len
&& !isspace(buf
[espaces
]); espaces
++);
1520 /* allocate space for the arg */
1521 if (0 == (retour
[i
] = malloc(sizeof(char) * (espaces
- j
) + 1))) {
1522 /* free what has been allocated */
1523 for (j
= 0; j
< i
; j
++)
1527 memcpy(retour
[i
], buf
+ j
, espaces
- j
);
1528 retour
[i
][espaces
- j
] = '\0';
1536 int readConfigFile( char *filename
){
1537 char buf
[CONF_BUFLEN
];
1538 char tmp
[CONF_BUFLEN
];
1542 if( (fp
= fopen( filename
, "r")) == 0 ){
1543 sprintf(config_file
, "%s/.wmpop3rc", getenv("HOME"));
1544 fprintf(stderr
, "-Config file does not exit : %s\n",config_file
);
1545 fprintf(stderr
, "+Trying to create new config file.\n");
1546 if((fp
= fopen(config_file
,"w")) == 0){
1547 fprintf(stderr
, "-Error creating new config file\n");
1550 fprintf(fp
, "#####################################################\n");
1551 fprintf(fp
, "# wmpop3lb configuration file #\n");
1552 fprintf(fp
, "# #\n");
1553 fprintf(fp
, "# for more information about wmpop3lb, please see: #\n");
1554 fprintf(fp
, "# http://wmpop3lb.jourdain.org #\n");
1555 fprintf(fp
, "# or send a mail to #\n");
1556 fprintf(fp
, "# wmpop3lb@jourdain.org #\n");
1557 fprintf(fp
, "#####################################################\n");
1558 fprintf(fp
, "autochecking 0 # 1 enables, 0 disables\n");
1559 fprintf(fp
, "displaydelay 2 # nb of seconds error info is displayed\n");
1560 fprintf(fp
, "scrollspeed 100 # percentage of original scrool speed\n");
1561 fprintf(fp
, "tempdir /tmp # directory for tmp files\n");
1562 fprintf(fp
, "viewallmessages 0 # 0 Shows the from and subject\n");
1563 fprintf(fp
, "# 1 Shows the number of messages\n");
1564 fprintf(fp
, "#\n# Replace all values with appropriate data\n#\n");
1565 fprintf(fp
, "[Server] # server section\n");
1566 fprintf(fp
, "alias \"3 alphanum. char. long alias\"\n");
1567 fprintf(fp
, "popserver \" pop3 server name \"\n");
1568 fprintf(fp
, "port 110 # default port\n");
1569 fprintf(fp
, "username \" pop3 login name \"\n");
1570 fprintf(fp
, "password \" pop3 password \"\n");
1571 fprintf(fp
, "mailcheckdelay 10 # default mail check time in minutes\n");
1572 fprintf(fp
, "countUnreadOnly 0 # count unread messages only\n");
1573 fprintf(fp
, "mailclient \"netscape -mail\" # for example...\n");
1574 fprintf(fp
, "newmailcommand \" specify new mail command \"\n");
1575 fprintf(fp
, "selectedmesgcommand \"specify command for selected mess\"\n");
1576 fprintf(fp
, "mailseparator \" separator when concatening messages\"\n");
1577 fprintf(fp
, "maxdlsize -1 # (no limit)\n");
1578 fprintf(fp
, "#\n# start new [server] section below (up to a total of 6)\n");
1579 fprintf(stderr
, "+New config file created : ~/.wmpop3rc\n\n");
1580 fprintf(stderr
, "+ ~/.wmpop3rc must be configured before running wmpop3.\n");
1588 while ((nb_conf
< 7) && fgets(buf
, CONF_BUFLEN
, fp
) != 0) {
1589 if (buf
[0] != '#') {
1590 if (!nb_conf
&& !strncasecmp( buf
, "autochecking", 12) ){
1591 if (parsenum(buf
+ 12, &autoChecking
))
1592 fprintf(stderr
, "syntax error for parameter autochecking\n");
1594 else if (!nb_conf
&& !strncasecmp( buf
, "scrollspeed", 11) ){
1595 if (parsenum(buf
+ 11, &scrollspeed
))
1596 fprintf(stderr
, "syntax error for parameter scrollspeed\n");
1598 else if (!nb_conf
&& !strncasecmp( buf
, "displaydelay", 12) ){
1599 if (parsenum(buf
+ 12, &displaydelay
))
1600 fprintf(stderr
, "syntax error for parameter displaydelay\n");
1602 else if (!nb_conf
&& !strncasecmp(buf
, "tempdir", 7)) {
1603 if (parsestring(buf
+ 7, tempdir
, 1024, fp
))
1604 fprintf(stderr
, "syntax error for parameter tempdir\n");
1606 else if (!strncasecmp(buf
, "[server]", 8)) {
1608 if (!(conf
[nb_conf
- 1] = pop3Create(nb_conf
))) {
1609 fprintf(stderr
, "Can't allocate memory for config structure\n");
1614 else if (nb_conf
&& !strncasecmp(buf
, "username", 8) ) {
1615 if (parsestring(buf
+ 8, conf
[nb_conf
-1]->username
, 256, fp
))
1616 fprintf(stderr
, "section %d: invalid syntax for username\n",
1619 else if (nb_conf
&& !strncasecmp( buf
, "password", 8) ){
1620 if (parsestring(buf
+ 8, conf
[nb_conf
- 1]->password
, 256, fp
))
1621 fprintf(stderr
, "section %d: invalid syntax for password\n",
1624 else if (nb_conf
&& !strncasecmp(buf
, "alias", 5) ) {
1625 if (parsestring(buf
+ 5, conf
[nb_conf
-1]->alias
, 3, fp
))
1626 fprintf(stderr
, "section %d: invalid syntax for alias\n", nb_conf
);
1628 else if (nb_conf
&& !strncasecmp( buf
, "popserver", 9) ){
1629 if (parsestring(buf
+ 9, conf
[nb_conf
- 1]->popserver
, 128, fp
))
1630 fprintf(stderr
, "section %d: invalid syntax for popserver\n",
1633 else if (nb_conf
&& !strncasecmp( buf
, "port", 4) ){
1634 if (parsenum(buf
+ 4, &(conf
[nb_conf
- 1]->serverport
)))
1635 fprintf(stderr
, "section %d: Invalid popserver port number.\n",
1638 else if (!nb_conf
&& !strncasecmp( buf
, "viewallmessages", 15) ){
1639 if (parsenum(buf
+ 15, &newMessagesOnly
))
1640 fprintf(stderr
, "section %d: Invalid number ( viewallmessages )\n",
1643 else if (nb_conf
&& !strncasecmp(buf
, "countunreadonly", 15)) {
1644 if (parsenum(buf
+ 15, &(conf
[nb_conf
- 1]->countunreadonly
)))
1645 fprintf(stderr
, "section %d: Invalid number ( countunreadonly )\n",
1648 else if (nb_conf
&& !strncasecmp( buf
, "mailcheckdelay", 14) ){
1649 if (parsenum(buf
+ 14, &(conf
[nb_conf
-1]->mailCheckDelay
)))
1650 fprintf(stderr
, "section %d: Invalid delay time.\n", nb_conf
);
1652 else if (nb_conf
&& !strncasecmp(buf
, "mailclient", 10)) {
1653 if (parsestring(buf
+ 10, tmp
, 256, fp
))
1654 fprintf(stderr
, "section %d: Invalid syntax for mailclient.\n",
1657 conf
[nb_conf
- 1]->mailclient
= build_arg_list(tmp
, strlen(tmp
));
1659 else if (nb_conf
&& !strncasecmp(buf
, "newmailcommand", 14)) {
1660 if (parsestring(buf
+ 14, tmp
, 256, fp
))
1661 fprintf(stderr
,"section %d: Invalid syntax for newmailcommand.\n",
1664 conf
[nb_conf
- 1]->newmailcommand
=
1665 build_arg_list(tmp
, strlen(tmp
));
1667 else if (nb_conf
&& !strncasecmp(buf
, "selectedmesgcommand", 19)) {
1668 if (parsestring(buf
+ 19, tmp
, 256, fp
))
1670 "section %d: Invalid syntax for selectedmesgcommand.\n",
1673 conf
[nb_conf
- 1]->selectedmesgcommand
=
1674 build_arg_list(tmp
, strlen(tmp
));
1676 else if (nb_conf
&& !strncasecmp(buf
, "mailseparator", 13)) {
1677 if (parsestring(buf
+ 13, conf
[nb_conf
- 1]->mailseparator
, 256, fp
))
1678 fprintf(stderr
, "section %d: Invalid syntax for mailseparator\n",
1681 else if (nb_conf
&& !strncasecmp( buf
, "maxdlsize", 9) ){
1682 if (parsenum(buf
+ 9, &(conf
[nb_conf
-1]->maxdlsize
)))
1683 fprintf(stderr
, "section %d: Invalid maxdlsize.\n", nb_conf
);
1686 if (*buf
&& (isalpha(*buf
) || isalnum(*buf
)))
1687 fprintf(stderr
, "section %d: Unknown indentifier : [%s]\n",
1691 for (bal
= buf
; *bal
&& !isalnum(*bal
); bal
++);
1693 fprintf(stderr
, "identifier outside Server section: [%s]\n", buf
);