1 /* Author : Louis-Benoit JOURDAIN (lb@jourdain.org)
2 * based on the original work by Scott Holden ( scotth@thezone.net )
4 * multi Pop3 Email checker.
6 * Last Updated : Feb 7th, 2002
11 #include "Pop3Client.h"
13 #include <sys/types.h>
14 #include <sys/socket.h>
15 #include <netinet/in.h>
23 #include <X11/extensions/shape.h>
25 #include <libdockapp/wmgeneral.h>
27 #include "Pop3Client.h"
29 /* return size if all goes well, -1 if not expected answer */
30 int send_command(char *exp_answer
, char **retour
, Pop3 pc
)
34 send(pc
->s
, &pc
->outBuf
,strlen(pc
->outBuf
),0);
35 size
= recv(pc
->s
,pc
->inBuf
,1024,0);
36 memset(*retour
,0,1024);
37 memcpy(*retour
,pc
->inBuf
,size
);
38 if (strncmp(pc
->inBuf
, exp_answer
, strlen(exp_answer
))) {
44 Pop3
pop3Create(int num
)
48 pc
= (Pop3
)malloc( sizeof(*pc
) );
51 memset(pc
, 0, sizeof(*pc
));
52 pc
->connected
= NOT_CONNECTED
;
54 pc
->mailCheckDelay
= 10;
55 /* make sure we perform an action first time we receive mail */
59 sprintf(pc
->alias
, "nb%d", num
);
62 int pop3MakeConnection(Pop3 pc
, char *serverName
, int port
){
64 pc
->s
= socket(AF_INET
, SOCK_STREAM
, 0 );
65 memset( &(pc
->server
), 0 , sizeof(pc
->server
));
66 pc
->server
.sin_family
= AF_INET
;
67 pc
->hp
= gethostbyname(serverName
);
70 memcpy( &(pc
->server
.sin_addr
), pc
->hp
->h_addr
, pc
->hp
->h_length
);
71 pc
->server
.sin_port
= htons(port
);
72 if ( connect(pc
->s
, (struct sockaddr
*)&(pc
->server
)
73 , sizeof(pc
->server
)) < 0 )
75 pc
->connected
= CONNECTED
;
79 int pop3IsConnected(Pop3 pc
){
81 if( pc
->connected
== CONNECTED
)
86 int pop3Login(Pop3 pc
, char *name
, char *pass
){
91 if( pc
->connected
== NOT_CONNECTED
){
92 perror("Not Connected To Server\n");
96 size
= recv(pc
->s
,&pc
->inBuf
,1024,0);
98 memcpy(temp
,pc
->inBuf
,size
);
100 fprintf(stderr
,"Error Logging in\n");
104 sprintf(pc
->outBuf
,"USER %s\r\n",name
);
105 send(pc
->s
, &pc
->outBuf
,strlen(pc
->outBuf
),0);
106 size
=recv(pc
->s
,pc
->inBuf
,1024,0);
108 memcpy(temp
,pc
->inBuf
,size
);
109 if( temp
[0] != '+' ){
110 fprintf(stderr
,"Invalid User Name\n");
114 memset(pc
->outBuf
,0,1024);
115 sprintf(pc
->outBuf
,"PASS %s\r\n",pass
);
116 send(pc
->s
, pc
->outBuf
, strlen(pc
->outBuf
),0 );
117 size
=recv(pc
->s
,&pc
->inBuf
,1024,0);
119 memcpy(temp
,pc
->inBuf
,size
);
120 if( temp
[0] != '+' ){
121 fprintf(stderr
,"Incorrect Password\n");
128 int store_from(char *buf
, int pos
, int buflen
, int num
, Pop3 pc
) {
134 /* strip the white spaces */
135 for (; (pos
< buflen
) && isspace(buf
[pos
]); pos
++);
136 /* get the end of the line */
137 for (end
= pos
; (end
+ 1 < buflen
) &&
138 (buf
[end
] != '\r') && (buf
[end
+ 1] != '\n'); end
++);
139 /* try to find the '@' sign for the address */
140 for (i
= pos
; (i
< end
) && buf
[i
] != '@'; i
++);
141 if (i
< end
) { /* we found a @ sign before the end of the line */
142 for (deb_addr
= i
; deb_addr
> pos
&& !isspace(buf
[deb_addr
]); deb_addr
--);
143 while (isspace(buf
[deb_addr
]) || ('<' == buf
[deb_addr
]))
145 for (fin_addr
= i
; fin_addr
< end
&& !isspace(buf
[fin_addr
]); fin_addr
++);
146 if ('>' == buf
[fin_addr
- 1])
148 memcpy(pc
->mails
[num
].from
, buf
+ deb_addr
,
149 (fin_addr
- deb_addr
> MAIL_BUFLEN
) ?
150 MAIL_BUFLEN
: fin_addr
- deb_addr
);
153 memcpy(pc
->mails
[num
].from
, buf
+ pos
,
154 (end
- pos
> MAIL_BUFLEN
) ? MAIL_BUFLEN
: end
- pos
);
159 int store_subject(char *buf
, int pos
, int buflen
, int num
, Pop3 pc
) {
163 /* get the end of the line */
164 for (end
= pos
, i
= 0; (i
< MAIL_BUFLEN
) && (end
+ 1 < buflen
) &&
165 (buf
[end
] != '\r') && (buf
[end
+ 1] != '\n'); end
++, i
++);
166 for (; (pos
< buflen
) && (buf
[pos
] == ' '); pos
++);
167 memcpy(pc
->mails
[num
].subject
, buf
+ pos
, end
- pos
);
171 int parse_header(char *buf
, int buflen
, int num
, Pop3 pc
) {
175 /* parse the header for the from and subject fields */
177 printf(" parse_header, buflen: %d, num %d, buf:\n%s\n",
180 while (pos
< buflen
) {
181 if ((buflen
> (pos
+ 2)) && !strncmp(".\r\n", buf
+ pos
, 3)) {
182 /* this is the end */
186 else if ((buflen
> (pos
+ 4)) && !strncmp("From:", buf
+ pos
, 5)) {
188 pos
= store_from(buf
, pos
, buflen
, num
, pc
);
190 else if ((buflen
> (pos
+ 7)) && !strncmp("Subject:", buf
+ pos
, 8)) {
192 pos
= store_subject(buf
, pos
, buflen
, num
, pc
);
195 for( ; (buflen
> (pos
+ 2)) && (buf
[pos
] != '\r') &&
196 (buf
[pos
+ 1] != '\n'); pos
++);
203 int pop3VerifStats(Pop3 pc
)
209 if( pc
->connected
== NOT_CONNECTED
)
212 /* Find total number of messages in mail box */
213 sprintf(pc
->outBuf
,"STAT\r\n");
214 send(pc
->s
, pc
->outBuf
, strlen(pc
->outBuf
),0 );
215 size
= recv(pc
->s
,pc
->inBuf
,1024,0);
216 if( pc
->inBuf
[0] != '+' ){
217 perror("Error Receiving Stats");
220 ptr
= strtok(pc
->inBuf
, " ");
221 ptr
= strtok( 0," ");
222 ptr
= strtok( 0, " ");
228 long calculate_cksum(char *buf
, int len
) {
232 for (i
= 0, cumul
= 0; i
< len
; i
++) {
233 cumul
+= (long) buf
[i
];
238 int is_in_old_mails(long cksum
, t_mail
*oldmails
, int numold
) {
241 for (i
= 0; i
< numold
; i
++) {
242 if (oldmails
[i
].cksum
== cksum
)
248 int pop3CheckMail(Pop3 pc
) {
255 int old_sizeOfAllMessages
;
256 int old_numOfMessages
;
257 int progressbarpos
= 0;
260 if( pc
->connected
== NOT_CONNECTED
)
262 /* save the old values */
263 old_sizeOfAllMessages
= pc
->sizeOfAllMessages
;
264 old_numOfMessages
= pc
->numOfMessages
;
265 /* Find total number of messages in mail box */
266 sprintf(pc
->outBuf
,"STAT\r\n");
267 send(pc
->s
, pc
->outBuf
, strlen(pc
->outBuf
),0 );
268 size
= recv(pc
->s
,pc
->inBuf
,1024,0);
269 pc
->inBuf
[size
] = '\0';
271 printf(" pop3CheckMail, stat received buf (size=%d): [%s]\n",
275 memcpy(temp
,pc
->inBuf
,size
);
276 if( temp
[0] != '+' ){
278 printf(" Error Receiving Stats: [%s]\n", temp
);
283 ptr
= strtok(temp
, " ");
284 ptr
= strtok( 0," ");
285 pc
->numOfMessages
= atoi(ptr
);
287 /* save the old messages */
288 oldmails
= pc
->mails
;
290 /* allocate space for the new ones */
291 if (pc
->numOfMessages
) {
293 (pc
->mails
= (t_mail
*) malloc (sizeof(t_mail
) * pc
->numOfMessages
))) {
294 fprintf(stderr
, "can't allocate memory for message structure\n");
295 /* clear the old messages */
301 /* Display the progress bar */
302 copyXPMArea(ORIG_PB_TX
, ORIG_PB_TY
, PROGRESSBAR_LEN
, PROGRESSBAR_HEI
,
303 PROGRESSBAR_HPOS
, PROGRESSBAR_VPOS
);
307 ptr
= strtok( 0, " ");
308 pc
->sizeOfAllMessages
= atoi(ptr
);
309 /* -1 means first time */
310 if (-1 != pc
->sizechanged
)
311 pc
->sizechanged
= (old_sizeOfAllMessages
!= pc
->sizeOfAllMessages
);
313 sprintf(pc
->outBuf
,"LAST\r\n");
314 send(pc
->s
, pc
->outBuf
, strlen(pc
->outBuf
),0 );
315 size
= recv(pc
->s
,pc
->inBuf
,1024,0);
316 pc
->inBuf
[size
] = '\0';
318 printf(" pop3CheckMail, last received buf (size=%d): [%s]\n",
322 memcpy(temp
,pc
->inBuf
,size
);
323 if( temp
[0] != '+' ){
325 printf(" Error Receiving LAST: [%s]\n", temp
);
327 pc
->numOfUnreadMessages
= pc
->numOfMessages
;
330 ptr
= strtok(temp
, " ");
331 ptr
= strtok( 0," ");
332 pc
->numOfUnreadMessages
= pc
->numOfMessages
- atoi(ptr
);
334 /* get the subject and From fields of numOfMessages mails */
335 for (i
= 0; i
< pc
->numOfMessages
; i
++) {
337 printf(" ---- message %d ---\n", i
);
339 /* increment the progress bar by 1 message */
340 progressbarpos
= (int) ((i
+ 1) * (PROGRESSBAR_LEN
- 2)) /
342 copyXPMArea(ORIG_PB_BARX
, ORIG_PB_BARY
, progressbarpos
, 2,
343 PROGRESSBAR_HPOS
+ 1, PROGRESSBAR_VPOS
+ 2);
345 /* reset the from and subject fields for num */
346 memset(&pc
->mails
[i
], 0, sizeof(t_mail
));
347 sprintf(pc
->outBuf
, "TOP %d 0\r\n", i
+ 1);
348 send(pc
->s
, pc
->outBuf
, strlen(pc
->outBuf
), 0);
351 while (go
&& (0 < (size
= recv(pc
->s
,pc
->inBuf
,4096,0)))) {
352 memset(temp
, 0, 4096);
353 memcpy(temp
, pc
->inBuf
, size
);
354 if (!pass
&& (temp
[0] != '+')) {
355 fprintf(stderr
, "Error while getting TOP %d 0\n", i
+ 1);
357 /* must set the from and subject fields to correct value */
358 strncpy(pc
->mails
[i
].from
, "::error::", 9);
361 /* calculate the checksum */
362 pc
->mails
[i
].cksum
+= calculate_cksum(temp
, size
);
364 go
= parse_header(temp
, size
, i
, pc
);
366 pc
->mails
[i
].todelete
= 0;
367 /* verify if this message is new or not */
368 pc
->mails
[i
].new = !is_in_old_mails(pc
->mails
[i
].cksum
, oldmails
,
371 printf(" mess %d, cksum: %ld, new: %d\n",
372 i
, pc
->mails
[i
].cksum
, pc
->mails
[i
].new);
375 /* clear the old messages */
382 int pop3WriteOneMail(int nb
, int dest_fd
, Pop3 pc
)
392 int theemailsize
= 0;
393 int mustdisconnect
= 0;
396 if (NOT_CONNECTED
== pc
->connected
) {
398 printf(" pop3WriteOneMail not connected, connecting\n");
400 if (pop3MakeConnection(pc
,pc
->popserver
,pc
->serverport
) == -1){
403 if (pop3Login(pc
, pc
->username
, pc
->password
) == -1) {
410 printf(" pc->maxdlsize = [%d]\n", pc
->maxdlsize
);
412 if (-1 != pc
->maxdlsize
) {
413 sprintf(pc
->outBuf
, "LIST %d\r\n", nb
);
415 printf(" pop3WriteOneMail: %s", pc
->outBuf
);
417 send(pc
->s
, pc
->outBuf
, strlen(pc
->outBuf
), 0);
418 size
= recv(pc
->s
, pc
->inBuf
, 4096, 0);
420 printf(" received %d bytes\n", size
);
422 memset(temp
, 0, 4096);
423 memcpy(temp
, pc
->inBuf
, size
);
425 printf(" pop3WriteOneMail: answer [%s]\n", temp
);
427 if (temp
[0] != '+') {
428 sprintf(buf
, TXT_ERROR
, pc
->mails
[nb
- 1].from
,
429 pc
->mails
[nb
- 1].subject
, pc
->outBuf
);
430 write (dest_fd
, buf
, strlen(buf
));
432 printf(" bad answer: [%s]\n", pc
->inBuf
);
436 /* go get the size of the email, strip +OK */
437 for (deb
= temp
; *deb
&& !isspace(*deb
); deb
++);
438 /* strip the spaces */
439 for (; *deb
&& isspace(*deb
); deb
++);
440 /* strip the email number */
441 for (; *deb
&& !isspace(*deb
); deb
++);
442 /* strip the last spaces */
443 for (; *deb
&& isspace(*deb
); deb
++);
444 /* go to the end of the size */
445 for (fin
= deb
; *fin
&& !isspace(*fin
); fin
++);
447 memcpy(buf
, deb
, fin
- deb
);
448 buf
[fin
- deb
] = '\0';
449 theemailsize
= atoi(buf
);
451 printf(" email retrieved size: %d\n", theemailsize
);
453 if (theemailsize
> pc
->maxdlsize
) {
454 sprintf(buf
, TXT_MESSAGETOOBIG
, pc
->mails
[nb
- 1].from
,
455 pc
->mails
[nb
- 1].subject
, theemailsize
, pc
->maxdlsize
);
456 write (dest_fd
, buf
, strlen(buf
));
458 printf(" email too big, return\n");
464 the command is screwed up, never mind, continue to download the mail */
468 sprintf(pc
->outBuf
, "RETR %d\r\n", nb
);
470 printf(" pop3WriteOneMail: %s", pc
->outBuf
);
472 send(pc
->s
, pc
->outBuf
, strlen(pc
->outBuf
), 0);
473 while (go
&& (size
= recv(pc
->s
, pc
->inBuf
, 4096, 0))) {
475 printf(" received %d bytes\n", size
);
477 memset(temp
, 0, 4096);
478 memcpy(temp
, pc
->inBuf
, size
);
481 if (temp
[0] != '+') {
482 sprintf(buf
, TXT_ERROR
, pc
->mails
[nb
- 1].from
,
483 pc
->mails
[nb
- 1].subject
, pc
->outBuf
);
484 write (dest_fd
, buf
, strlen(buf
));
490 printf(" first pass, skeep RETR answer ([%s])\n", deb
);
492 /* skip the RETR answer, go to the end of the line; */
493 for (;*deb
&& ('\n' != *deb
); deb
++);
496 /* check if these are the final bits of the message */
497 fin
= temp
+ size
- 5;
499 printf(" size: %d, fin: [%s]\n", size
, fin
);
502 if (!strncmp(fin
, "\r\n.\r\n", 5)) {
504 /* don't write the final '.' into the message, skip it*/
507 printf(" skeeping final '.', new size=%d\n", size
);
514 printf(" buffer (long: %d):\n[%s]\n", (temp
+ size
) - deb
, deb
);
517 while (deb
< (temp
+ size
)) {
518 len
= write(dest_fd
, deb
, (temp
+ size
) - deb
);
522 printf(" wrote %d bytes\n", len
);
526 if (mustdisconnect
) {
528 printf(" pop3WriteOneMail disconnecting\n");
533 printf(" pop3WriteOneMail, return\n");
538 int pop3DeleteMail(int num
, Pop3 pc
)
542 sprintf(pc
->outBuf
, "DELE %d\r\n", num
);
544 printf(" %s\n", pc
->outBuf
);
546 send(pc
->s
, pc
->outBuf
, strlen(pc
->outBuf
), 0);
547 size
= recv(pc
->s
, pc
->inBuf
, 4096, 0);
548 if ('+' != pc
->inBuf
[0]) {
549 perror("error while deleting mail");
558 int pop3GetTotalNumberOfMessages( Pop3 pc
){
560 return pc
->numOfMessages
;
564 int pop3GetNumberOfUnreadMessages( Pop3 pc
){
566 return pc
->numOfUnreadMessages
;
570 int pop3Quit(Pop3 pc
){
574 printf("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n");
575 printf("XXXXXX pop3Quit -------- disconneting XXXXXXXXX\n");
576 printf("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n");
578 if( pc
->connected
== NOT_CONNECTED
)
580 send(pc
->s
, "quit\r\n", 6,0 );
581 size
=recv(pc
->s
,&pc
->inBuf
,1024,0);
582 pc
->connected
= NOT_CONNECTED
;