wmcore: set DESTDIR so binary installs correctly.
[dockapps.git] / wmpop3lb / wmpop3 / Pop3Client.c
blob7b219a96499a614f8f73bdc5f33aa254b750f21f
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
8 */
11 #include "Pop3Client.h"
12 #include <string.h>
13 #include <sys/types.h>
14 #include <sys/socket.h>
15 #include <netinet/in.h>
16 #include <netdb.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <unistd.h>
21 #include <X11/xpm.h>
22 #include <X11/Xlib.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)
32 int size;
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))) {
39 return (-1);
41 return (size);
44 Pop3 pop3Create(int num)
46 Pop3 pc;
48 pc = (Pop3)malloc( sizeof(*pc) );
49 if( pc == 0)
50 return 0;
51 memset(pc, 0, sizeof(*pc));
52 pc->connected = NOT_CONNECTED;
53 pc->serverport = 110;
54 pc->mailCheckDelay = 10;
55 /* make sure we perform an action first time we receive mail */
56 pc->forcedCheck = 1;
57 pc->sizechanged = -1;
58 pc->maxdlsize = -1;
59 sprintf(pc->alias, "nb%d", num);
60 return (pc);
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);
68 if( pc->hp == 0)
69 return -1;
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 )
74 return -1;
75 pc->connected = CONNECTED;
76 return 0;
79 int pop3IsConnected(Pop3 pc){
81 if( pc->connected == CONNECTED)
82 return 1;
83 return 0;
86 int pop3Login(Pop3 pc, char *name, char *pass){
88 int size;
89 char temp[1024];
91 if( pc->connected == NOT_CONNECTED ){
92 perror("Not Connected To Server\n");
93 return -1;
96 size = recv(pc->s,&pc->inBuf,1024,0);
97 memset(temp,0,1024);
98 memcpy(temp,pc->inBuf,size);
99 if( temp[0] != '+' ){
100 fprintf(stderr,"Error Logging in\n");
101 return -1;
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);
107 memset(temp,0,1024);
108 memcpy(temp,pc->inBuf,size);
109 if( temp[0] != '+' ){
110 fprintf(stderr,"Invalid User Name\n");
111 return -1;
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);
118 memset(temp,0,1024);
119 memcpy(temp,pc->inBuf,size);
120 if( temp[0] != '+' ){
121 fprintf(stderr,"Incorrect Password\n");
122 return -1;
125 return 0;
128 int store_from(char *buf, int pos, int buflen, int num, Pop3 pc) {
129 int end;
130 int deb_addr;
131 int fin_addr;
132 int i;
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]))
144 deb_addr++;
145 for (fin_addr = i; fin_addr < end && !isspace(buf[fin_addr]); fin_addr++);
146 if ('>' == buf[fin_addr - 1])
147 fin_addr--;
148 memcpy(pc->mails[num].from, buf + deb_addr,
149 (fin_addr - deb_addr > MAIL_BUFLEN) ?
150 MAIL_BUFLEN : fin_addr - deb_addr);
152 else {
153 memcpy(pc->mails[num].from, buf + pos,
154 (end - pos > MAIL_BUFLEN) ? MAIL_BUFLEN : end - pos);
156 return (end + 2);
159 int store_subject(char *buf, int pos, int buflen, int num, Pop3 pc) {
160 int end;
161 int i;
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);
168 return (end + 2);
171 int parse_header(char *buf, int buflen, int num, Pop3 pc) {
172 int pos = 0;
173 int retour = 1;
175 /* parse the header for the from and subject fields */
176 #ifdef _DEBUG
177 printf(" parse_header, buflen: %d, num %d, buf:\n%s\n",
178 buflen, num, buf);
179 #endif
180 while (pos < buflen) {
181 if ((buflen > (pos + 2)) && !strncmp(".\r\n", buf + pos, 3)) {
182 /* this is the end */
183 pos = buflen;
184 retour = 0;
186 else if ((buflen > (pos + 4)) && !strncmp("From:", buf + pos, 5)) {
187 pos += 5;
188 pos = store_from(buf, pos, buflen, num, pc);
190 else if ((buflen > (pos + 7)) && !strncmp("Subject:", buf + pos, 8)) {
191 pos += 8;
192 pos = store_subject(buf, pos, buflen, num, pc);
194 else {
195 for( ; (buflen > (pos + 2)) && (buf[pos] != '\r') &&
196 (buf[pos + 1] != '\n'); pos++);
197 pos += 2;
200 return (retour);
203 int pop3VerifStats(Pop3 pc)
205 int retour = 0;
206 char *ptr;
207 int size;
209 if( pc->connected == NOT_CONNECTED )
210 return (-1);
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");
218 return (-1);
220 ptr = strtok(pc->inBuf, " ");
221 ptr = strtok( 0," ");
222 ptr = strtok( 0, " ");
223 if (ptr)
224 retour = atoi(ptr);
225 return (retour);
228 long calculate_cksum(char *buf, int len) {
229 int i;
230 long cumul;
232 for (i = 0, cumul = 0; i < len; i++) {
233 cumul += (long) buf[i];
235 return (cumul);
238 int is_in_old_mails(long cksum, t_mail *oldmails, int numold) {
239 int i;
241 for (i = 0; i < numold; i++) {
242 if (oldmails[i].cksum == cksum)
243 return (1);
245 return (0);
248 int pop3CheckMail(Pop3 pc) {
249 int size;
250 char temp[4096];
251 char *ptr;
252 int i;
253 int pass;
254 int go;
255 int old_sizeOfAllMessages;
256 int old_numOfMessages;
257 int progressbarpos = 0;
258 t_mail *oldmails;
260 if( pc->connected == NOT_CONNECTED )
261 return -1;
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';
270 #ifdef _DEBUG
271 printf(" pop3CheckMail, stat received buf (size=%d): [%s]\n",
272 size, pc->inBuf);
273 #endif
274 memset(temp,0,1024);
275 memcpy(temp,pc->inBuf,size);
276 if( temp[0] != '+' ){
277 #ifdef _DEBUG
278 printf(" Error Receiving Stats: [%s]\n", temp);
279 #endif
280 return (-1);
283 ptr = strtok(temp, " ");
284 ptr = strtok( 0," ");
285 pc->numOfMessages = atoi(ptr);
287 /* save the old messages */
288 oldmails = pc->mails;
289 pc->mails = NULL;
290 /* allocate space for the new ones */
291 if (pc->numOfMessages) {
292 if (NULL ==
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 */
296 if (oldmails) {
297 free (oldmails);
299 return (-1);
301 /* Display the progress bar */
302 copyXPMArea(ORIG_PB_TX, ORIG_PB_TY, PROGRESSBAR_LEN, PROGRESSBAR_HEI,
303 PROGRESSBAR_HPOS, PROGRESSBAR_VPOS);
304 RedrawWindow();
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';
317 #ifdef _DEBUG
318 printf(" pop3CheckMail, last received buf (size=%d): [%s]\n",
319 size, pc->inBuf);
320 #endif
321 memset(temp,0,1024);
322 memcpy(temp,pc->inBuf,size);
323 if( temp[0] != '+' ){
324 #ifdef _DEBUG
325 printf(" Error Receiving LAST: [%s]\n", temp);
326 #endif
327 pc->numOfUnreadMessages = pc->numOfMessages;
329 else {
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++) {
336 #ifdef _DEBUG
337 printf(" ---- message %d ---\n", i);
338 #endif
339 /* increment the progress bar by 1 message */
340 progressbarpos = (int) ((i + 1) * (PROGRESSBAR_LEN - 2)) /
341 pc->numOfMessages;
342 copyXPMArea(ORIG_PB_BARX, ORIG_PB_BARY, progressbarpos, 2,
343 PROGRESSBAR_HPOS + 1, PROGRESSBAR_VPOS + 2);
344 RedrawWindow();
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);
349 pass = 0;
350 go = 1;
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);
356 go = 0;
357 /* must set the from and subject fields to correct value */
358 strncpy(pc->mails[i].from, "::error::", 9);
359 continue;
361 /* calculate the checksum */
362 pc->mails[i].cksum += calculate_cksum(temp, size);
363 pass++;
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,
369 old_numOfMessages);
370 #ifdef _DEBUG
371 printf(" mess %d, cksum: %ld, new: %d\n",
372 i, pc->mails[i].cksum, pc->mails[i].new);
373 #endif
375 /* clear the old messages */
376 if (oldmails) {
377 free (oldmails);
379 return 1;
382 int pop3WriteOneMail(int nb, int dest_fd, Pop3 pc)
384 int len;
385 int retour = 0;
386 char buf[4096];
387 char temp[4096];
388 int size;
389 int pass = 0;
390 int go = 1;
391 char *deb, *fin;
392 int theemailsize = 0;
393 int mustdisconnect = 0;
396 if (NOT_CONNECTED == pc->connected) {
397 #ifdef _DEBUG
398 printf(" pop3WriteOneMail not connected, connecting\n");
399 #endif
400 if (pop3MakeConnection(pc,pc->popserver,pc->serverport) == -1){
401 return (1);
403 if (pop3Login(pc, pc->username, pc->password) == -1) {
404 return (1);
406 mustdisconnect = 1;
408 /* check the size */
409 #ifdef _DEBUG
410 printf(" pc->maxdlsize = [%d]\n", pc->maxdlsize);
411 #endif
412 if (-1 != pc->maxdlsize) {
413 sprintf(pc->outBuf, "LIST %d\r\n", nb);
414 #ifdef _DEBUG
415 printf(" pop3WriteOneMail: %s", pc->outBuf);
416 #endif
417 send(pc->s, pc->outBuf, strlen(pc->outBuf), 0);
418 size = recv(pc->s, pc->inBuf, 4096, 0);
419 #ifdef _DEBUG
420 printf(" received %d bytes\n", size);
421 #endif
422 memset(temp, 0, 4096);
423 memcpy(temp, pc->inBuf, size);
424 #ifdef _DEBUG
425 printf(" pop3WriteOneMail: answer [%s]\n", temp);
426 #endif
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));
431 #ifdef _DEBUG
432 printf(" bad answer: [%s]\n", pc->inBuf);
433 #endif
434 return (0);
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++);
446 if (*deb && *fin) {
447 memcpy(buf, deb, fin - deb);
448 buf[fin - deb] = '\0';
449 theemailsize = atoi(buf);
450 #ifdef _DEBUG
451 printf(" email retrieved size: %d\n", theemailsize);
452 #endif
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));
457 #ifdef _DEBUG
458 printf(" email too big, return\n");
459 #endif
460 return (0);
463 /* else {}
464 the command is screwed up, never mind, continue to download the mail */
468 sprintf(pc->outBuf, "RETR %d\r\n", nb);
469 #ifdef _DEBUG
470 printf(" pop3WriteOneMail: %s", pc->outBuf);
471 #endif
472 send(pc->s, pc->outBuf, strlen(pc->outBuf), 0);
473 while (go && (size = recv(pc->s, pc->inBuf, 4096, 0))) {
474 #ifdef _DEBUG
475 printf(" received %d bytes\n", size);
476 #endif
477 memset(temp, 0, 4096);
478 memcpy(temp, pc->inBuf, size);
479 deb = temp;
480 if (!pass) {
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));
485 retour = 1;
486 go = 0;
487 continue;
489 #ifdef _DEBUG
490 printf(" first pass, skeep RETR answer ([%s])\n", deb);
491 #endif
492 /* skip the RETR answer, go to the end of the line; */
493 for (;*deb && ('\n' != *deb); deb++);
494 deb++;
496 /* check if these are the final bits of the message */
497 fin = temp + size - 5;
498 #ifdef _DEBUG
499 printf(" size: %d, fin: [%s]\n", size, fin);
500 #endif
501 if (size >= 5) {
502 if (!strncmp(fin, "\r\n.\r\n", 5)) {
503 go = 0;
504 /* don't write the final '.' into the message, skip it*/
505 size -= 3;
506 #ifdef _DEBUG
507 printf(" skeeping final '.', new size=%d\n", size);
508 #endif
511 else
512 go = 0;
513 #ifdef _DEBUG
514 printf(" buffer (long: %d):\n[%s]\n", (temp + size) - deb, deb);
515 #endif
516 len = 0;
517 while (deb < (temp + size)) {
518 len = write(dest_fd, deb, (temp + size) - deb);
519 deb += len;
521 #ifdef _DEBUG
522 printf(" wrote %d bytes\n", len);
523 #endif
524 pass++;
526 if (mustdisconnect) {
527 #ifdef _DEBUG
528 printf(" pop3WriteOneMail disconnecting\n");
529 #endif
530 pop3Quit(pc);
532 #ifdef _DEBUG
533 printf(" pop3WriteOneMail, return\n");
534 #endif
535 return (retour);
538 int pop3DeleteMail(int num, Pop3 pc)
540 int size;
542 sprintf(pc->outBuf, "DELE %d\r\n", num);
543 #ifdef _DEBUG
544 printf(" %s\n", pc->outBuf);
545 #endif
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");
550 return (1);
552 return (0);
558 int pop3GetTotalNumberOfMessages( Pop3 pc ){
559 if( pc != 0 )
560 return pc->numOfMessages;
561 return -1;
564 int pop3GetNumberOfUnreadMessages( Pop3 pc ){
565 if( pc != 0)
566 return pc->numOfUnreadMessages;
567 return -1;
570 int pop3Quit(Pop3 pc){
571 int size;
573 #ifdef _DEBUG
574 printf("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n");
575 printf("XXXXXX pop3Quit -------- disconneting XXXXXXXXX\n");
576 printf("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n");
577 #endif
578 if( pc->connected == NOT_CONNECTED )
579 return -1;
580 send(pc->s, "quit\r\n", 6,0 );
581 size =recv(pc->s,&pc->inBuf,1024,0);
582 pc->connected = NOT_CONNECTED;
583 if(pc->s != 0)
584 close(pc->s);
585 return 0;