Commit d22b2199 d22b2199ab813bf994afc2dbe8e033ffcc01d045 by Sergey Poznyakoff

Minor change in stream API. Improve POP3 client interface.

* include/mailutils/sys/stream.h (_MU_STR_EVENT_SET)
(_MU_STR_EVENT_CLR): New defines.
(_mu_stream) <event_cb, event_mask>: New members.
* mailbox/stream.c (_stream_setflag, _stream_clrflag): New static
functions.
All functions use these instead of setting/clearing flags directly.
(_mu_stream_cleareof, _mu_stream_seteof): New extern functions.
(_stream_cleareof): Remove define, use _mu_stream_cleareof instead.
(_stream_fill_buffer): Set EOF marker when end of stream is reached.

* mailbox/fltstream.c (filter_read): Call _mu_stream_seteof to set
EOF flag.

* include/mailutils/pop3.h: Get rid of the superfluous "extern" in
front of function prototypes.
Add new prototypes.
Remove extra whitespace.

* libproto/pop/pop3_capatst.c: New file.
* libproto/pop/pop3_list_cmd.c: New file.
* libproto/pop/pop3_listas.c: New file.
* libproto/pop/pop3_rdlist.c: New file.
* libproto/pop/pop3_uidl_cmd.c: New file.
* libproto/pop/pop3_uidlas.c: New file.
* libproto/pop/Makefile.am: Add new files.
* libproto/pop/pop3_capa.c (_mu_pop3_fill_list): Remove.
Use mu_pop3_read_list instead.
(capa_comp): New comparator for capa lists.
* libproto/pop/pop3_list.c (mu_pop3_list): Fix format specifier.
* libproto/pop/pop3_lista.c (mu_pop3_list_all): Rewrite.
* libproto/pop/pop3_retr.c (mu_pop3_retr) <MU_POP3_RETR_RX>: do not
reset state, this is done by the EOF event callback.
* libproto/pop/pop3_top.c (mu_pop3_top) <MU_POP3_TOP_RX>: Likewise.
* libproto/pop/pop3_stream.c (pop3_decode_state): New state pds_char.
Change semantics of pds_init.
(newstate, _pop3_decoder): Handle .\r\n in the initial state.
(_pop3_event_cb): New event callback.
(mu_pop3_filter_create): Set event callback on the filter stream.
* libproto/pop/pop3_uidla.c (mu_pop3_uidl_all): Rewrite.

* examples/Makefile.am (pop3client_CPPFLAGS): Add MU_APP_COMMON_INCLUDES.
* examples/pop3client.c: Rewrite command parser.
1 parent b94a6d3c
...@@ -111,6 +111,7 @@ sfrom_LDADD =\ ...@@ -111,6 +111,7 @@ sfrom_LDADD =\
111 @MU_AUTHLIBS@\ 111 @MU_AUTHLIBS@\
112 ${MU_LIB_MAILUTILS} 112 ${MU_LIB_MAILUTILS}
113 113
114 pop3client_CPPFLAGS = @MU_APP_COMMON_INCLUDES@
114 pop3client_LDADD = \ 115 pop3client_LDADD = \
115 ../lib/libmuaux.la\ 116 ../lib/libmuaux.la\
116 ${MU_LIB_POP}\ 117 ${MU_LIB_POP}\
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
34 #include <stdlib.h> 34 #include <stdlib.h>
35 #include <termios.h> 35 #include <termios.h>
36 #include <signal.h> 36 #include <signal.h>
37 #include <xalloc.h>
37 38
38 #ifdef WITH_READLINE 39 #ifdef WITH_READLINE
39 # include <readline/readline.h> 40 # include <readline/readline.h>
...@@ -56,64 +57,81 @@ ...@@ -56,64 +57,81 @@
56 typedef struct 57 typedef struct
57 { 58 {
58 const char *name; /* User printable name of the function. */ 59 const char *name; /* User printable name of the function. */
59 int (*func) (char *); /* Function to call to do the job. */ 60 int argmin;
61 int argmax;
62 int (*func) (int, char **); /* Function to call to do the job. */
60 const char *doc; /* Documentation for this function. */ 63 const char *doc; /* Documentation for this function. */
61 } 64 }
62 COMMAND; 65 COMMAND;
63 66
64 /* The names of functions that actually do the manipulation. */ 67 /* The names of functions that actually do the manipulation. */
65 int com_apop (char *); 68 int com_apop (int, char **);
66 int com_capa (char *); 69 int com_capa (int, char **);
67 int com_disconnect (char *); 70 int com_disconnect (int, char **);
68 int com_dele (char *); 71 int com_dele (int, char **);
69 int com_exit (char *); 72 int com_exit (int, char **);
70 int com_help (char *); 73 int com_help (int, char **);
71 int com_list (char *); 74 int com_list (int, char **);
72 int com_noop (char *); 75 int com_noop (int, char **);
73 int com_connect (char *); 76 int com_connect (int, char **);
74 int com_pass (char *); 77 int com_pass (int, char **);
75 int com_quit (char *); 78 int com_quit (int, char **);
76 int com_retr (char *); 79 int com_retr (int, char **);
77 int com_rset (char *); 80 int com_rset (int, char **);
78 int com_stat (char *); 81 int com_stat (int, char **);
79 int com_top (char *); 82 int com_top (int, char **);
80 int com_uidl (char *); 83 int com_uidl (int, char **);
81 int com_user (char *); 84 int com_user (int, char **);
82 int com_verbose (char *); 85 int com_verbose (int, char **);
83 int com_prompt (char *); 86 int com_prompt (int, char **);
84 int com_stls (char *); 87 int com_stls (int, char **);
85
86 void initialize_readline (void);
87 COMMAND *find_command (char *);
88 char *dupstr (const char *);
89 int execute_line (char *);
90 int valid_argument (const char *, char *);
91 88
92 void sig_int (int); 89 COMMAND *find_command (char *);
93 90
94 COMMAND commands[] = { 91 COMMAND commands[] = {
95 { "apop", com_apop, "Authenticate with APOP: APOP user secret" }, 92 { "apop", 3, 3, com_apop,
96 { "capa", com_capa, "List capabilities: capa" }, 93 "Authenticate with APOP: APOP user secret" },
97 { "disconnect", com_disconnect, "Close connection: disconnect" }, 94 { "capa", 1, -1, com_capa,
98 { "dele", com_dele, "Mark message: DELE msgno" }, 95 "List capabilities: capa [-reread] [names...]" },
99 { "exit", com_exit, "exit program" }, 96 { "disconnect", 1, 1,
100 { "help", com_help, "Display this text" }, 97 com_disconnect, "Close connection: disconnect" },
101 { "?", com_help, "Synonym for `help'" }, 98 { "dele", 2, 2, com_dele,
102 { "list", com_list, "List messages: LIST [msgno]" }, 99 "Mark message: DELE msgno" },
103 { "noop", com_noop, "Send no operation: NOOP" }, 100 { "exit", 1, 1, com_exit,
104 { "pass", com_pass, "Send passwd: PASS [passwd]" }, 101 "exit program" },
105 { "prompt", com_prompt, "Set command prompt" }, 102 { "help", 1, 1, com_help,
106 { "connect", com_connect, "Open connection: connect hostname [port]" }, 103 "Display this text" },
107 { "quit", com_quit, "Go to Update state : QUIT" }, 104 { "?", 1, 1, com_help,
108 { "retr", com_retr, "Dowload message: RETR msgno" }, 105 "Synonym for `help'" },
109 { "rset", com_rset, "Unmark all messages: RSET" }, 106 { "list", 1, 2, com_list,
110 { "stat", com_stat, "Get the size and count of mailbox : STAT [msgno]" }, 107 "List messages: LIST [msgno]" },
111 { "stls", com_stls, "Start TLS negotiation" }, 108 { "noop", 1, 1, com_noop,
112 { "top", com_top, "Get the header of message: TOP msgno [lines]" }, 109 "Send no operation: NOOP" },
113 { "uidl", com_uidl, "Get the unique id of message: UIDL [msgno]" }, 110 { "pass", 1, 2, com_pass,
114 { "user", com_user, "send login: USER user" }, 111 "Send passwd: PASS [passwd]" },
115 { "verbose", com_verbose, "Enable Protocol tracing: verbose [on|off]" }, 112 { "prompt", -1, -1, com_prompt,
116 { NULL, NULL, NULL } 113 "Set command prompt" },
114 { "connect", 1, 4, com_connect,
115 "Open connection: connect [-tls] hostname port" },
116 { "quit", 1, 1, com_quit,
117 "Go to Update state : QUIT" },
118 { "retr", 2, 2, com_retr,
119 "Dowload message: RETR msgno" },
120 { "rset", 1, 1, com_rset,
121 "Unmark all messages: RSET" },
122 { "stat", 1, 1, com_stat,
123 "Get the size and count of mailbox : STAT" },
124 { "stls", 1, 1, com_stls,
125 "Start TLS negotiation" },
126 { "top", 2, 3, com_top,
127 "Get the header of message: TOP msgno [lines]" },
128 { "uidl", 1, 2, com_uidl,
129 "Get the unique id of message: UIDL [msgno]" },
130 { "user", 2, 2, com_user,
131 "send login: USER user" },
132 { "verbose", 1, 2, com_verbose,
133 "Enable Protocol tracing: verbose [on|off]" },
134 { NULL }
117 }; 135 };
118 136
119 /* Global handle for pop3. */ 137 /* Global handle for pop3. */
...@@ -189,20 +207,6 @@ expand_prompt () ...@@ -189,20 +207,6 @@ expand_prompt ()
189 return str; 207 return str;
190 } 208 }
191 209
192 char *
193 dupstr (const char *s)
194 {
195 char *r;
196
197 r = malloc (strlen (s) + 1);
198 if (!r)
199 {
200 mu_error ("Memory exhausted");
201 exit (1);
202 }
203 strcpy (r, s);
204 return r;
205 }
206 210
207 211
208 #ifdef WITH_READLINE 212 #ifdef WITH_READLINE
...@@ -269,7 +273,7 @@ command_generator (const char *text, int state) ...@@ -269,7 +273,7 @@ command_generator (const char *text, int state)
269 list_index++; 273 list_index++;
270 274
271 if (strncmp (name, text, len) == 0) 275 if (strncmp (name, text, len) == 0)
272 return (dupstr (name)); 276 return xstrdup (name);
273 } 277 }
274 278
275 /* If no names matched, then return NULL. */ 279 /* If no names matched, then return NULL. */
...@@ -304,73 +308,103 @@ add_history (const char *s MU_ARG_UNUSED) ...@@ -304,73 +308,103 @@ add_history (const char *s MU_ARG_UNUSED)
304 } 308 }
305 #endif 309 #endif
306 310
311 int
312 get_bool (const char *str, int *pb)
313 {
314 if (mu_c_strcasecmp (str, "yes") == 0
315 || mu_c_strcasecmp (str, "on") == 0
316 || mu_c_strcasecmp (str, "true") == 0)
317 *pb = 1;
318 else if (mu_c_strcasecmp (str, "no") == 0
319 || mu_c_strcasecmp (str, "off") == 0
320 || mu_c_strcasecmp (str, "false") == 0)
321 *pb = 0;
322 else
323 {
324 mu_error ("not a boolean: %s", str);
325 return 1;
326 }
327 return 0;
328 }
307 329
308 int 330 int
309 main (int argc MU_ARG_UNUSED, char **argv) 331 get_port (const char *port_str, int *pn)
310 { 332 {
311 char *line, *s; 333 short port_num;
334 long num;
335 char *p;
312 336
313 mu_set_program_name (argv[0]); 337 num = port_num = strtol (port_str, &p, 0);
314 prompt = strdup (DEFAULT_PROMPT); 338 if (*p == 0)
315 initialize_readline (); /* Bind our completer. */
316 #ifdef WITH_TLS
317 mu_init_tls_libs ();
318 #endif
319 /* Loop reading and executing lines until the user quits. */
320 while (!done)
321 { 339 {
322 char *p = expand_prompt (); 340 if (num != port_num)
323 line = readline (p);
324 free (p);
325
326 if (!line)
327 break;
328
329 /* Remove leading and trailing whitespace from the line.
330 Then, if there is anything left, add it to the history list
331 and execute it. */
332 s = mu_str_stripws (line);
333
334 if (*s)
335 { 341 {
336 int status; 342 mu_error ("bad port number: %s", port_str);
337 add_history (s); 343 return 1;
338 status = execute_line (s);
339 if (status != 0)
340 mu_error ("Error: %s", mu_strerror (status));
341 } 344 }
342
343 free (line);
344 } 345 }
345 exit (0); 346 else
347 {
348 struct servent *sp = getservbyname (port_str, "tcp");
349 if (!sp)
350 {
351 mu_error ("unknown port name");
352 return 1;
353 }
354 port_num = ntohs (sp->s_port);
355 }
356 *pn = port_num;
357 return 0;
346 } 358 }
347 359
348 /* Parse and execute a command line. */ 360 /* Parse and execute a command line. */
349 int 361 int
350 execute_line (char *line) 362 execute_line (char *line)
351 { 363 {
352 COMMAND *command; 364 int argc;
353 char *word, *arg; 365 char **argv;
366 int status = 0;
354 367
355 /* Isolate the command word. */ 368 if (mu_argcv_get (line, NULL, "#", &argc, &argv))
356 word = mu_str_skip_class (line, MU_CTYPE_SPACE);
357 arg = mu_str_skip_class_comp (word, MU_CTYPE_SPACE);
358 if (*arg)
359 { 369 {
360 *arg++ = 0; 370 mu_error("cannot parse input line");
361 arg = mu_str_skip_class (arg, MU_CTYPE_SPACE); 371 return 0;
362 } 372 }
363 373
364 command = find_command (word); 374 if (argc >= 0)
375 {
376 COMMAND *command = find_command (argv[0]);
365 377
366 if (!command) 378 if (!command)
379 mu_error ("%s: no such command.", argv[0]);
380 else if (command->argmin > 0 && argc < command->argmin)
381 mu_error ("%s: too few arguments", argv[0]);
382 else if (command->argmax > 0 && argc > command->argmax)
383 mu_error ("%s: too many arguments", argv[0]);
384 else
367 { 385 {
368 mu_error ("%s: No such command.", word); 386 if (command->argmin <= 0 && argc != 2)
369 return 0; 387 {
388 char *word = mu_str_skip_class (line, MU_CTYPE_SPACE);
389 char *arg = mu_str_skip_class_comp (word, MU_CTYPE_SPACE);
390 if (*arg)
391 {
392 *arg++ = 0;
393 arg = mu_str_skip_class (arg, MU_CTYPE_SPACE);
370 } 394 }
371 395
372 /* Call the function. */ 396 mu_argcv_free (argc, argv);
373 return ((*(command->func)) (arg)); 397 argc = 2;
398 argv = xcalloc (argc + 1, sizeof (argv[0]));
399 argv[0] = xstrdup (word);
400 argv[1] = xstrdup (arg);
401 argv[2] = NULL;
402 }
403 status = command->func (argc, argv);
404 }
405 }
406 mu_argcv_free (argc, argv);
407 return status;
374 } 408 }
375 409
376 /* Look up NAME as the name of a command, and return a pointer to that 410 /* Look up NAME as the name of a command, and return a pointer to that
...@@ -378,23 +412,32 @@ execute_line (char *line) ...@@ -378,23 +412,32 @@ execute_line (char *line)
378 COMMAND * 412 COMMAND *
379 find_command (char *name) 413 find_command (char *name)
380 { 414 {
381 register int i; 415 COMMAND *cp;
382 416
383 for (i = 0; commands[i].name; i++) 417 for (cp = commands; cp->name; cp++)
384 if (strcmp (name, commands[i].name) == 0) 418 if (strcmp (cp->name, name) == 0)
385 return (&commands[i]); 419 return cp;
386 420
387 return ((COMMAND *) NULL); 421 return NULL;
388 } 422 }
389 423
390 int 424 int
391 com_verbose (char *arg) 425 com_verbose (int argc, char **argv)
392 { 426 {
393 int status = 0; 427 if (argc == 1)
394 if (!valid_argument ("verbose", arg)) 428 {
395 return EINVAL; 429 if (verbose)
430 printf ("verbose is on\n");
431 else
432 printf ("verbose is off\n");
433 }
434 else
435 {
436 int bv;
396 437
397 verbose = (strcmp (arg, "on") == 0); 438 if (get_bool (argv[1], &bv) == 0)
439 {
440 verbose = bv;
398 if (pop3 != NULL) 441 if (pop3 != NULL)
399 { 442 {
400 if (verbose == 1) 443 if (verbose == 1)
...@@ -402,61 +445,84 @@ com_verbose (char *arg) ...@@ -402,61 +445,84 @@ com_verbose (char *arg)
402 else 445 else
403 mu_pop3_trace (pop3, MU_POP3_TRACE_CLR); 446 mu_pop3_trace (pop3, MU_POP3_TRACE_CLR);
404 } 447 }
405 return status; 448 }
449 }
450 return 0;
406 } 451 }
407 452
408 int 453 int
409 com_user (char *arg) 454 com_user (int argc, char **argv)
410 { 455 {
411 int status; 456 int status;
412 457
413 if (!valid_argument ("user", arg)) 458 status = mu_pop3_user (pop3, argv[1]);
414 return EINVAL;
415 status = mu_pop3_user (pop3, arg);
416 if (status == 0) 459 if (status == 0)
417 username = strdup (arg); 460 username = strdup (argv[1]);
418 return status; 461 return status;
419 } 462 }
420 463
421 int 464 int
422 com_apop (char *arg) 465 com_apop (int argc, char **argv)
423 { 466 {
424 int status; 467 int status;
425 char *user, *digest; 468
426 469 status = mu_pop3_apop (pop3, argv[1], argv[2]);
427 if (!valid_argument ("apop", arg))
428 return EINVAL;
429 user = strtok (arg, " ");
430 digest = strtok (NULL, " ");
431 if (!valid_argument ("apop", user) || !valid_argument ("apop", digest))
432 return EINVAL;
433 status = mu_pop3_apop (pop3, user, digest);
434 if (status == 0) 470 if (status == 0)
435 { 471 {
436 username = strdup (user); 472 username = strdup (argv[1]);
437 pop_session_status = pop_session_logged_in; 473 pop_session_status = pop_session_logged_in;
438 } 474 }
439 return status; 475 return status;
440 } 476 }
441 477
442 int 478 int
443 com_capa (char *arg) 479 com_capa (int argc, char **argv)
444 { 480 {
445 mu_iterator_t iterator = NULL; 481 mu_iterator_t iterator = NULL;
446 int status; 482 int status = 0;
447 int reread = 0; 483 int reread = 0;
484 int i = 1;
448 485
449 if (arg && *arg) 486 for (i = 1; i < argc; i++)
450 { 487 {
451 if (strcmp (arg, "reread") == 0) 488 if (strcmp (argv[i], "-reread") == 0)
452 reread = 1; 489 reread = 1;
453 else 490 else
454 { 491 break;
455 mu_error ("%s: unknown argument", "capa");
456 return 0;
457 } 492 }
493
494 if (i < argc)
495 {
496 if (reread)
497 {
498 status = mu_pop3_capa (pop3, 1, NULL);
499 if (status)
500 return status;
458 } 501 }
502 for (; i < argc; i++)
503 {
504 const char *elt;
505 int rc = pop3_capa_test (pop3, argv[i], &elt);
506 switch (rc)
507 {
508 case 0:
509 if (*elt)
510 printf ("%s: %s\n", argv[i], elt);
511 else
512 printf ("%s is set\n", argv[i]);
513 break;
514
515 case MU_ERR_NOENT:
516 printf ("%s is not set\n", argv[i]);
517 break;
459 518
519 default:
520 return rc;
521 }
522 }
523 }
524 else
525 {
460 status = mu_pop3_capa (pop3, reread, &iterator); 526 status = mu_pop3_capa (pop3, reread, &iterator);
461 527
462 if (status == 0) 528 if (status == 0)
...@@ -466,18 +532,19 @@ com_capa (char *arg) ...@@ -466,18 +532,19 @@ com_capa (char *arg)
466 { 532 {
467 char *capa = NULL; 533 char *capa = NULL;
468 mu_iterator_current (iterator, (void **) &capa); 534 mu_iterator_current (iterator, (void **) &capa);
469 printf ("Capa: %s\n", (capa) ? capa : ""); 535 printf ("CAPA: %s\n", capa ? capa : "");
470 } 536 }
471 mu_iterator_destroy (&iterator); 537 mu_iterator_destroy (&iterator);
472 } 538 }
539 }
473 return status; 540 return status;
474 } 541 }
475 542
476 int 543 int
477 com_uidl (char *arg) 544 com_uidl (int argc, char **argv)
478 { 545 {
479 int status = 0; 546 int status = 0;
480 if (arg == NULL || *arg == '\0') 547 if (argc == 1)
481 { 548 {
482 mu_iterator_t uidl_iterator = NULL; 549 mu_iterator_t uidl_iterator = NULL;
483 status = mu_pop3_uidl_all (pop3, &uidl_iterator); 550 status = mu_pop3_uidl_all (pop3, &uidl_iterator);
...@@ -489,7 +556,7 @@ com_uidl (char *arg) ...@@ -489,7 +556,7 @@ com_uidl (char *arg)
489 { 556 {
490 char *uidl = NULL; 557 char *uidl = NULL;
491 mu_iterator_current (uidl_iterator, (void **) &uidl); 558 mu_iterator_current (uidl_iterator, (void **) &uidl);
492 printf ("UIDL: %s\n", (uidl) ? uidl : ""); 559 printf ("UIDL: %s\n", uidl ? uidl : "");
493 } 560 }
494 mu_iterator_destroy (&uidl_iterator); 561 mu_iterator_destroy (&uidl_iterator);
495 } 562 }
...@@ -497,20 +564,20 @@ com_uidl (char *arg) ...@@ -497,20 +564,20 @@ com_uidl (char *arg)
497 else 564 else
498 { 565 {
499 char *uidl = NULL; 566 char *uidl = NULL;
500 unsigned int msgno = strtoul (arg, NULL, 10); 567 unsigned int msgno = strtoul (argv[1], NULL, 10);
501 status = mu_pop3_uidl (pop3, msgno, &uidl); 568 status = mu_pop3_uidl (pop3, msgno, &uidl);
502 if (status == 0) 569 if (status == 0)
503 printf ("Msg: %d UIDL: %s\n", msgno, (uidl) ? uidl : ""); 570 printf ("Msg: %d UIDL: %s\n", msgno, uidl ? uidl : "");
504 free (uidl); 571 free (uidl);
505 } 572 }
506 return status; 573 return status;
507 } 574 }
508 575
509 int 576 int
510 com_list (char *arg) 577 com_list (int argc, char **argv)
511 { 578 {
512 int status = 0; 579 int status = 0;
513 if (arg == NULL || *arg == '\0') 580 if (argc == 1)
514 { 581 {
515 mu_iterator_t list_iterator; 582 mu_iterator_t list_iterator;
516 status = mu_pop3_list_all (pop3, &list_iterator); 583 status = mu_pop3_list_all (pop3, &list_iterator);
...@@ -530,7 +597,7 @@ com_list (char *arg) ...@@ -530,7 +597,7 @@ com_list (char *arg)
530 else 597 else
531 { 598 {
532 size_t size = 0; 599 size_t size = 0;
533 unsigned int msgno = strtoul (arg, NULL, 10); 600 unsigned int msgno = strtoul (argv[1], NULL, 10);
534 status = mu_pop3_list (pop3, msgno, &size); 601 status = mu_pop3_list (pop3, msgno, &size);
535 if (status == 0) 602 if (status == 0)
536 printf ("Msg: %u Size: %lu\n", msgno, (unsigned long) size); 603 printf ("Msg: %u Size: %lu\n", msgno, (unsigned long) size);
...@@ -539,7 +606,7 @@ com_list (char *arg) ...@@ -539,7 +606,7 @@ com_list (char *arg)
539 } 606 }
540 607
541 int 608 int
542 com_noop (char *arg MU_ARG_UNUSED) 609 com_noop (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED)
543 { 610 {
544 return mu_pop3_noop (pop3); 611 return mu_pop3_noop (pop3);
545 } 612 }
...@@ -561,33 +628,31 @@ echo_on (struct termios *stored_settings) ...@@ -561,33 +628,31 @@ echo_on (struct termios *stored_settings)
561 } 628 }
562 629
563 int 630 int
564 com_prompt (char *arg) 631 com_prompt (int argc, char **argv)
565 { 632 {
566 int quote; 633 int quote;
567 size_t size; 634 size_t size;
568 635
569 if (!valid_argument ("prompt", arg))
570 return EINVAL;
571
572 free (prompt); 636 free (prompt);
573 size = mu_argcv_quoted_length (arg, &quote); 637 size = mu_argcv_quoted_length (argv[1], &quote);
574 prompt = malloc (size + 1); 638 prompt = malloc (size + 1);
575 if (!prompt) 639 if (!prompt)
576 { 640 {
577 mu_error ("Memory exhausted"); 641 mu_error ("Memory exhausted");
578 exit (1); 642 exit (1);
579 } 643 }
580 mu_argcv_unquote_copy (prompt, arg, size); 644 mu_argcv_unquote_copy (prompt, argv[1], size);
581 return 0; 645 return 0;
582 } 646 }
583 647
584 int 648 int
585 com_pass (char *arg) 649 com_pass (int argc, char **argv)
586 { 650 {
587 int status; 651 int status;
588 char pass[256]; 652 char pass[256];
653 char *pwd;
589 654
590 if (!arg || *arg == '\0') 655 if (argc == 1)
591 { 656 {
592 struct termios stored_settings; 657 struct termios stored_settings;
593 658
...@@ -599,16 +664,18 @@ com_pass (char *arg) ...@@ -599,16 +664,18 @@ com_pass (char *arg)
599 putchar ('\n'); 664 putchar ('\n');
600 fflush (stdout); 665 fflush (stdout);
601 pass[strlen (pass) - 1] = '\0'; /* nuke the trailing line. */ 666 pass[strlen (pass) - 1] = '\0'; /* nuke the trailing line. */
602 arg = pass; 667 pwd = pass;
603 } 668 }
604 status = mu_pop3_pass (pop3, arg); 669 else
670 pwd = argv[1];
671 status = mu_pop3_pass (pop3, pwd);
605 if (status == 0) 672 if (status == 0)
606 pop_session_status = pop_session_logged_in; 673 pop_session_status = pop_session_logged_in;
607 return status; 674 return status;
608 } 675 }
609 676
610 int 677 int
611 com_stat (char *arg MU_ARG_UNUSED) 678 com_stat (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED)
612 { 679 {
613 unsigned count = 0; 680 unsigned count = 0;
614 size_t size = 0; 681 size_t size = 0;
...@@ -621,32 +688,31 @@ com_stat (char *arg MU_ARG_UNUSED) ...@@ -621,32 +688,31 @@ com_stat (char *arg MU_ARG_UNUSED)
621 } 688 }
622 689
623 int 690 int
624 com_stls (char *arg MU_ARG_UNUSED) 691 com_stls (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED)
625 { 692 {
626 return mu_pop3_stls (pop3); 693 return mu_pop3_stls (pop3);
627 } 694 }
628 695
629 int 696 int
630 com_dele (char *arg) 697 com_dele (int argc, char **argv)
631 { 698 {
632 unsigned msgno; 699 unsigned msgno;
633 if (!valid_argument ("dele", arg)) 700 msgno = strtoul (argv[1], NULL, 10);
634 return EINVAL;
635 msgno = strtoul (arg, NULL, 10);
636 return mu_pop3_dele (pop3, msgno); 701 return mu_pop3_dele (pop3, msgno);
637 } 702 }
638 703
639 /* Print out help for ARG, or for all of the commands if ARG is 704 /* Print out help for ARG, or for all of the commands if ARG is
640 not present. */ 705 not present. */
641 int 706 int
642 com_help (char *arg) 707 com_help (int argc, char **argv)
643 { 708 {
644 int i; 709 int i;
645 int printed = 0; 710 int printed = 0;
711 char *name = argv[1];
646 712
647 for (i = 0; commands[i].name; i++) 713 for (i = 0; commands[i].name; i++)
648 { 714 {
649 if (!*arg || (strcmp (arg, commands[i].name) == 0)) 715 if (!name || (strcmp (name, commands[i].name) == 0))
650 { 716 {
651 printf ("%s\t\t%s.\n", commands[i].name, commands[i].doc); 717 printf ("%s\t\t%s.\n", commands[i].name, commands[i].doc);
652 printed++; 718 printed++;
...@@ -655,7 +721,7 @@ com_help (char *arg) ...@@ -655,7 +721,7 @@ com_help (char *arg)
655 721
656 if (!printed) 722 if (!printed)
657 { 723 {
658 printf ("No commands match `%s'. Possibilties are:\n", arg); 724 printf ("No commands match `%s'. Possibilties are:\n", name);
659 725
660 for (i = 0; commands[i].name; i++) 726 for (i = 0; commands[i].name; i++)
661 { 727 {
...@@ -677,32 +743,24 @@ com_help (char *arg) ...@@ -677,32 +743,24 @@ com_help (char *arg)
677 } 743 }
678 744
679 int 745 int
680 com_rset (char *arg MU_ARG_UNUSED) 746 com_rset (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED)
681 { 747 {
682 return mu_pop3_rset (pop3); 748 return mu_pop3_rset (pop3);
683 } 749 }
684 750
685 int 751 int
686 com_top (char *arg) 752 com_top (int argc, char **argv)
687 { 753 {
688 mu_stream_t stream; 754 mu_stream_t stream;
689 unsigned int msgno; 755 unsigned int msgno;
690 unsigned int lines; 756 unsigned int lines;
691 char *space;
692 int status; 757 int status;
693 758
694 if (!valid_argument ("top", arg)) 759 msgno = strtoul (argv[1], NULL, 10);
695 return EINVAL; 760 if (argc == 3)
696 761 lines = strtoul (argv[2], NULL, 10);
697 space = strchr (arg, ' ');
698 if (space)
699 {
700 *space++ = '\0';
701 lines = strtoul (space, NULL, 10);
702 }
703 else 762 else
704 lines = 0; 763 lines = 5;
705 msgno = strtoul (arg, NULL, 10);
706 764
707 status = mu_pop3_top (pop3, msgno, lines, &stream); 765 status = mu_pop3_top (pop3, msgno, lines, &stream);
708 766
...@@ -718,16 +776,13 @@ com_top (char *arg) ...@@ -718,16 +776,13 @@ com_top (char *arg)
718 } 776 }
719 777
720 int 778 int
721 com_retr (char *arg) 779 com_retr (int argc, char **argv)
722 { 780 {
723 mu_stream_t stream; 781 mu_stream_t stream;
724 unsigned int msgno; 782 unsigned int msgno;
725 int status; 783 int status;
726 784
727 if (!valid_argument ("retr", arg)) 785 msgno = strtoul (argv[1], NULL, 10);
728 return EINVAL;
729
730 msgno = strtoul (arg, NULL, 10);
731 status = mu_pop3_retr (pop3, msgno, &stream); 786 status = mu_pop3_retr (pop3, msgno, &stream);
732 787
733 if (status == 0) 788 if (status == 0)
...@@ -742,73 +797,44 @@ com_retr (char *arg) ...@@ -742,73 +797,44 @@ com_retr (char *arg)
742 } 797 }
743 798
744 int 799 int
745 get_port (const char *port_str, int *pn) 800 com_connect (int argc, char **argv)
746 { 801 {
747 short port_num; 802 int status;
748 long num; 803 int n = 0;
749 char *p; 804 int tls = 0;
805 int i = 1;
750 806
751 num = port_num = strtol (port_str, &p, 0); 807 for (i = 1; i < argc; i++)
752 if (*p == 0)
753 { 808 {
754 if (num != port_num) 809 if (strcmp (argv[i], "-tls") == 0)
755 { 810 {
756 mu_error ("bad port number: %s", port_str); 811 if (WITH_TLS)
757 return 1; 812 tls = 1;
758 }
759 }
760 else 813 else
761 { 814 {
762 struct servent *sp = getservbyname (port_str, "tcp"); 815 mu_error ("TLS not supported");
763 if (!sp)
764 {
765 mu_error ("unknown port name");
766 return 1;
767 }
768 port_num = ntohs (sp->s_port);
769 }
770 *pn = port_num;
771 return 0;
772 }
773
774 int
775 com_connect (char *arg)
776 {
777 int status;
778 int n = 110;
779 int argc;
780 char **argv;
781
782 if (!valid_argument ("connect", arg))
783 return 1;
784
785 if (mu_argcv_get (arg, NULL, NULL, &argc, &argv))
786 {
787 mu_error ("Cannot parse arguments");
788 return 0; 816 return 0;
789 } 817 }
790
791 if (!valid_argument ("connect", argv[0]))
792 {
793 mu_argcv_free (argc, argv);
794 return EINVAL;
795 } 818 }
796 819 else
797 if (argc > 2) 820 break;
798 {
799 mu_error ("Too many arguments");
800 mu_argcv_free (argc, argv);
801 return 0;
802 } 821 }
803 822
804 if (argc == 2 && get_port (argv[1], &n)) 823 argc -= i;
824 argv += i;
825
826 if (argc >= 2)
805 { 827 {
806 mu_argcv_free (argc, argv); 828 if (get_port (argv[1], &n))
807 return 0; 829 return 0;
808 } 830 }
831 else if (tls)
832 n = MU_POP3_DEFAULT_SSL_PORT;
833 else
834 n = MU_POP3_DEFAULT_PORT;
809 835
810 if (pop_session_status != pop_session_disconnected) 836 if (pop_session_status != pop_session_disconnected)
811 com_disconnect (NULL); 837 com_disconnect (0, NULL);
812 838
813 status = mu_pop3_create (&pop3); 839 status = mu_pop3_create (&pop3);
814 if (status == 0) 840 if (status == 0)
...@@ -816,10 +842,35 @@ com_connect (char *arg) ...@@ -816,10 +842,35 @@ com_connect (char *arg)
816 mu_stream_t tcp; 842 mu_stream_t tcp;
817 843
818 if (verbose) 844 if (verbose)
819 com_verbose ("on"); 845 mu_pop3_trace (pop3, MU_POP3_TRACE_SET);
820 status = mu_tcp_stream_create (&tcp, argv[0], n, MU_STREAM_READ); 846 status = mu_tcp_stream_create (&tcp, argv[0], n, MU_STREAM_READ);
821 if (status == 0) 847 if (status == 0)
822 { 848 {
849 #ifdef WITH_TLS
850 if (tls)
851 {
852 mu_stream_t tlsstream;
853
854 status = mu_stream_open (tcp);
855 if (status)
856 {
857 mu_error ("cannot open connection: %s",
858 mu_stream_strerror (tcp, status));
859 mu_stream_destroy (&tcp);
860 return 0;
861 }
862
863 status = mu_tls_client_stream_create (&tlsstream, tcp, tcp, 0);
864 mu_stream_unref (tcp);
865 if (status)
866 {
867 mu_error ("cannot create TLS stream: %s",
868 mu_strerror (status));
869 return 0;
870 }
871 tcp = tlsstream;
872 }
873 #endif
823 mu_pop3_set_carrier (pop3, tcp); 874 mu_pop3_set_carrier (pop3, tcp);
824 status = mu_pop3_connect (pop3); 875 status = mu_pop3_connect (pop3);
825 } 876 }
...@@ -831,14 +882,14 @@ com_connect (char *arg) ...@@ -831,14 +882,14 @@ com_connect (char *arg)
831 } 882 }
832 883
833 if (status) 884 if (status)
834 {
835 mu_error ("Failed to create pop3: %s", mu_strerror (status)); 885 mu_error ("Failed to create pop3: %s", mu_strerror (status));
836 mu_argcv_free (argc, argv);
837 }
838 else 886 else
839 { 887 {
840 connect_argc = argc; 888 connect_argc = argc;
841 connect_argv = argv; 889 connect_argv = xcalloc (argc, sizeof (*connect_argv));
890 for (i = 0; i < argc; i++)
891 connect_argv[i] = xstrdup (argv[i]);
892 connect_argv[i] = NULL;
842 port = n; 893 port = n;
843 pop_session_status = pop_session_connected; 894 pop_session_status = pop_session_connected;
844 } 895 }
...@@ -847,7 +898,7 @@ com_connect (char *arg) ...@@ -847,7 +898,7 @@ com_connect (char *arg)
847 } 898 }
848 899
849 int 900 int
850 com_disconnect (char *arg MU_ARG_UNUSED) 901 com_disconnect (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED)
851 { 902 {
852 if (pop3) 903 if (pop3)
853 { 904 {
...@@ -864,14 +915,14 @@ com_disconnect (char *arg MU_ARG_UNUSED) ...@@ -864,14 +915,14 @@ com_disconnect (char *arg MU_ARG_UNUSED)
864 } 915 }
865 916
866 int 917 int
867 com_quit (char *arg MU_ARG_UNUSED) 918 com_quit (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED)
868 { 919 {
869 int status = 0; 920 int status = 0;
870 if (pop3) 921 if (pop3)
871 { 922 {
872 if (mu_pop3_quit (pop3) == 0) 923 if (mu_pop3_quit (pop3) == 0)
873 { 924 {
874 status = com_disconnect (arg); 925 status = com_disconnect (0, NULL);
875 } 926 }
876 else 927 else
877 { 928 {
...@@ -884,7 +935,7 @@ com_quit (char *arg MU_ARG_UNUSED) ...@@ -884,7 +935,7 @@ com_quit (char *arg MU_ARG_UNUSED)
884 } 935 }
885 936
886 int 937 int
887 com_exit (char *arg MU_ARG_UNUSED) 938 com_exit (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED)
888 { 939 {
889 if (pop3) 940 if (pop3)
890 { 941 {
...@@ -895,16 +946,44 @@ com_exit (char *arg MU_ARG_UNUSED) ...@@ -895,16 +946,44 @@ com_exit (char *arg MU_ARG_UNUSED)
895 return 0; 946 return 0;
896 } 947 }
897 948
898 /* Return non-zero if ARG is a valid argument for CALLER, else print 949
899 an error message and return zero. */
900 int 950 int
901 valid_argument (const char *caller, char *arg) 951 main (int argc MU_ARG_UNUSED, char **argv)
902 { 952 {
903 if (!arg || !*arg) 953 char *line, *s;
954
955 mu_set_program_name (argv[0]);
956 prompt = strdup (DEFAULT_PROMPT);
957 initialize_readline (); /* Bind our completer. */
958 #ifdef WITH_TLS
959 mu_init_tls_libs ();
960 #endif
961 /* Loop reading and executing lines until the user quits. */
962 while (!done)
904 { 963 {
905 mu_error ("%s: Argument required", caller); 964 char *p = expand_prompt ();
906 return 0; 965 line = readline (p);
966 free (p);
967
968 if (!line)
969 break;
970
971 /* Remove leading and trailing whitespace from the line.
972 Then, if there is anything left, add it to the history list
973 and execute it. */
974 s = mu_str_stripws (line);
975
976 if (*s)
977 {
978 int status;
979 add_history (s);
980 status = execute_line (s);
981 if (status != 0)
982 mu_error ("Error: %s", mu_strerror (status));
907 } 983 }
908 984
909 return 1; 985 free (line);
986 }
987 exit (0);
910 } 988 }
989
......
...@@ -32,87 +32,99 @@ struct _mu_pop3; ...@@ -32,87 +32,99 @@ struct _mu_pop3;
32 typedef struct _mu_pop3 *mu_pop3_t; 32 typedef struct _mu_pop3 *mu_pop3_t;
33 33
34 #define MU_POP3_DEFAULT_PORT 110 34 #define MU_POP3_DEFAULT_PORT 110
35 #define MU_POP3_DEFAULT_SSL_PORT 995
35 36
36 extern int mu_pop3_create (mu_pop3_t *pop3); 37 int mu_pop3_create (mu_pop3_t *pop3);
37 extern void mu_pop3_destroy (mu_pop3_t *pop3); 38 void mu_pop3_destroy (mu_pop3_t *pop3);
38 39
39 extern int mu_pop3_set_carrier (mu_pop3_t pop3, mu_stream_t carrier); 40 int mu_pop3_set_carrier (mu_pop3_t pop3, mu_stream_t carrier);
40 extern int mu_pop3_get_carrier (mu_pop3_t pop3, mu_stream_t *pcarrier); 41 int mu_pop3_get_carrier (mu_pop3_t pop3, mu_stream_t *pcarrier);
41 42
42 extern int mu_pop3_connect (mu_pop3_t pop3); 43 int mu_pop3_connect (mu_pop3_t pop3);
43 extern int mu_pop3_disconnect (mu_pop3_t pop3); 44 int mu_pop3_disconnect (mu_pop3_t pop3);
44 45
45 extern int mu_pop3_set_timeout (mu_pop3_t pop3, int timeout); 46 int mu_pop3_set_timeout (mu_pop3_t pop3, int timeout);
46 extern int mu_pop3_get_timeout (mu_pop3_t pop3, int *timeout); 47 int mu_pop3_get_timeout (mu_pop3_t pop3, int *timeout);
47 48
48 #define MU_POP3_TRACE_CLR 0 49 #define MU_POP3_TRACE_CLR 0
49 #define MU_POP3_TRACE_SET 1 50 #define MU_POP3_TRACE_SET 1
50 #define MU_POP3_TRACE_QRY 2 51 #define MU_POP3_TRACE_QRY 2
51 extern int mu_pop3_trace (mu_pop3_t pop3, int op); 52 int mu_pop3_trace (mu_pop3_t pop3, int op);
52 53
53 extern int mu_pop3_apop (mu_pop3_t pop3, const char *name, const char *digest); 54 int mu_pop3_apop (mu_pop3_t pop3, const char *name, const char *digest);
54 55
55 extern int mu_pop3_stls (mu_pop3_t pop3); 56 int mu_pop3_stls (mu_pop3_t pop3);
56 57
57 /* It is the responsability of the caller to call mu_iterator_destroy() when 58 /* It is the responsability of the caller to call mu_iterator_destroy() when
58 done with the iterator. The items returned by the iterator are of type 59 done with the iterator. The items returned by the iterator are of type
59 "const char *", no processing is done on the item except the removal of 60 "const char *", no processing is done on the item except the removal of
60 the trailing newline. */ 61 the trailing newline. */
61 extern int mu_pop3_capa (mu_pop3_t pop3, int reread, 62 int mu_pop3_capa (mu_pop3_t pop3, int reread, mu_iterator_t *piter);
62 mu_iterator_t *piter); 63 int pop3_capa_test (mu_pop3_t pop3, const char *name, const char **pret);
63 64
64 extern int mu_pop3_dele (mu_pop3_t pop3, unsigned int mesgno); 65 int mu_pop3_dele (mu_pop3_t pop3, unsigned int mesgno);
65 66
66 extern int mu_pop3_list (mu_pop3_t pop3, unsigned int mesgno, size_t *mesg_octet); 67 int mu_pop3_list (mu_pop3_t pop3, unsigned int mesgno, size_t *mesg_octet);
67 68
68 /* An iterator is return with the multi-line answer. It is the responsability 69 /* Send the LIST command and prepare pop3 for receiving a multiline answer.
69 of the caller to call mu_iterator_destroy() to dispose of the iterator. */ 70 The caller is expected to obtain a stream via mu_pop3_stream_create,
70 extern int mu_pop3_list_all (mu_pop3_t pop3, mu_iterator_t *piterator); 71 or an iterator via mu_pop3_iterator_create and read data from them.
71 72
72 extern int mu_pop3_noop (mu_pop3_t pop3); 73 This function is not intended for use by a casual user, better use
74 mu_pop3_list_all or mu_pop3_list_all_stream. */
75 int mu_pop3_list_cmd (mu_pop3_t pop3);
76 int mu_pop3_list_all (mu_pop3_t pop3, mu_iterator_t *pitr);
77 int mu_pop3_list_all_stream (mu_pop3_t pop3, mu_stream_t *pstream);
73 78
74 extern int mu_pop3_pass (mu_pop3_t pop3, const char *pass); 79 int mu_pop3_noop (mu_pop3_t pop3);
75 80
76 extern int mu_pop3_quit (mu_pop3_t pop3); 81 int mu_pop3_pass (mu_pop3_t pop3, const char *pass);
82
83 int mu_pop3_quit (mu_pop3_t pop3);
77 84
78 /* A stream is returned with the multi-line answer. It is the responsability 85 /* A stream is returned with the multi-line answer. It is the responsability
79 of the caller to call mu_stream_destroy() to dipose of the stream. */ 86 of the caller to call mu_stream_destroy() to dipose of the stream. */
80 extern int mu_pop3_retr (mu_pop3_t pop3, unsigned int mesgno, 87 int mu_pop3_retr (mu_pop3_t pop3, unsigned int mesgno,
81 mu_stream_t *pstream); 88 mu_stream_t *pstream);
82 89
83 extern int mu_pop3_rset (mu_pop3_t pop3); 90 int mu_pop3_rset (mu_pop3_t pop3);
84 91
85 extern int mu_pop3_stat (mu_pop3_t pop3, unsigned int *count, 92 int mu_pop3_stat (mu_pop3_t pop3, unsigned int *count, size_t *octets);
86 size_t *octets);
87 93
88 /* A stream is returned with the multi-line answer. It is the responsability 94 /* A stream is returned with the multi-line answer. It is the responsability
89 of the caller to call mu_stream_destroy() to dipose of the stream. */ 95 of the caller to call mu_stream_destroy() to dipose of the stream. */
90 extern int mu_pop3_top (mu_pop3_t pop3, unsigned int mesgno, 96 int mu_pop3_top (mu_pop3_t pop3, unsigned int mesgno,
91 unsigned int lines, mu_stream_t *pstream); 97 unsigned int lines, mu_stream_t *pstream);
92 98
93 /* The uidl is malloc'ed and returned in puidl; it is the responsability of 99 /* The uidl is malloc'ed and returned in puidl; it is the responsability of
94 the caller to free() the uild when done. */ 100 the caller to free() the uild when done. */
95 extern int mu_pop3_uidl (mu_pop3_t pop3, unsigned int mesgno, 101 int mu_pop3_uidl (mu_pop3_t pop3, unsigned int mesgno, char **puidl);
96 char **puidl);
97 /* An iterator is returned with the multi-line answer. It is the
98 responsability of the caller to call mu_iterator_destroy() to dispose of
99 the iterator. */
100 extern int mu_pop3_uidl_all (mu_pop3_t pop3, mu_iterator_t *piterator);
101 102
102 extern int mu_pop3_user (mu_pop3_t pop3, const char *user); 103 /* Send the UIDL command and prepare pop3 for receiving a multiline answer.
104 The caller is expected to obtain a stream via mu_pop3_stream_create,
105 or an iterator via mu_pop3_iterator_create and read data from them.
103 106
107 This function is not intended for use by a casual user, better use
108 mu_pop3_uidl_all or mu_pop3_uidl_all_stream. */
109 int mu_pop3_uidl_all_cmd (mu_pop3_t pop3);
110 int mu_pop3_uidl_all (mu_pop3_t pop3, mu_iterator_t *piterator);
111 int mu_pop3_uidl_all_stream (mu_pop3_t pop3, mu_stream_t *pstream);
104 112
113 int mu_pop3_user (mu_pop3_t pop3, const char *user);
105 114
106 /* Returns the last command acknowledge. If the server supports RESP-CODE, 115 /* Returns the last command acknowledge. If the server supports RESP-CODE,
107 the message could be retrieved, but it is up to the caller to do the 116 the message could be retrieved, but it is up to the caller to do the
108 parsing. */ 117 parsing. */
109 extern int mu_pop3_response (mu_pop3_t pop3, size_t *nread); 118 int mu_pop3_response (mu_pop3_t pop3, size_t *nread);
110 119
111 extern int mu_pop3_writeline (mu_pop3_t pop3, const char *format, ...) 120 int mu_pop3_writeline (mu_pop3_t pop3, const char *format, ...)
112 MU_PRINTFLIKE(2,3); 121 MU_PRINTFLIKE(2,3);
113 122
114 extern int mu_pop3_sendline (mu_pop3_t pop3, const char *line); 123 int mu_pop3_sendline (mu_pop3_t pop3, const char *line);
115 extern int mu_pop3_getline (mu_pop3_t pop3); 124 int mu_pop3_getline (mu_pop3_t pop3);
125 int mu_pop3_read_list (mu_pop3_t pop3, mu_list_t list);
126 int mu_pop3_stream_to_list (mu_pop3_t pop3, mu_stream_t stream,
127 mu_list_t list);
116 128
117 #ifdef __cplusplus 129 #ifdef __cplusplus
118 } 130 }
......
...@@ -24,6 +24,9 @@ ...@@ -24,6 +24,9 @@
24 24
25 #define _MU_STR_INTERN_MASK 0xf000 25 #define _MU_STR_INTERN_MASK 0xf000
26 26
27 #define _MU_STR_EVENT_SET 1
28 #define _MU_STR_EVENT_CLR 2
29
27 struct _mu_stream 30 struct _mu_stream
28 { 31 {
29 int ref_count; 32 int ref_count;
...@@ -54,6 +57,9 @@ struct _mu_stream ...@@ -54,6 +57,9 @@ struct _mu_stream
54 int (*truncate) (struct _mu_stream *, mu_off_t); 57 int (*truncate) (struct _mu_stream *, mu_off_t);
55 int (*shutdown) (struct _mu_stream *, int); 58 int (*shutdown) (struct _mu_stream *, int);
56 59
60 void (*event_cb) (struct _mu_stream *, int, int);
61 int event_mask;
62
57 const char *(*error_string) (struct _mu_stream *, int); 63 const char *(*error_string) (struct _mu_stream *, int);
58 64
59 }; 65 };
...@@ -65,6 +71,9 @@ int mu_stream_write_unbuffered (mu_stream_t stream, ...@@ -65,6 +71,9 @@ int mu_stream_write_unbuffered (mu_stream_t stream,
65 const void *buf, size_t size, 71 const void *buf, size_t size,
66 int full_write, size_t *pnwritten); 72 int full_write, size_t *pnwritten);
67 73
74 void _mu_stream_cleareof (mu_stream_t str);
75 void _mu_stream_seteof (mu_stream_t str);
76
68 #define _MU_SWAP_FIRST_ONLY 0x01 77 #define _MU_SWAP_FIRST_ONLY 0x01
69 #define _MU_SWAP_IOCTL_MUST_SUCCEED 0x02 78 #define _MU_SWAP_IOCTL_MUST_SUCCEED 0x02
70 79
......
...@@ -25,12 +25,13 @@ libmu_pop_la_LDFLAGS=-version-info @VI_CURRENT@:@VI_REVISION@:@VI_AGE@ ...@@ -25,12 +25,13 @@ libmu_pop_la_LDFLAGS=-version-info @VI_CURRENT@:@VI_REVISION@:@VI_AGE@
25 libmu_pop_la_LIBADD = ${MU_LIB_AUTH} ${MU_LIB_MAILUTILS} @INTLLIBS@ 25 libmu_pop_la_LIBADD = ${MU_LIB_AUTH} ${MU_LIB_MAILUTILS} @INTLLIBS@
26 26
27 # folder.c\ 27 # folder.c\
28 # mbox.c\ 28 # url.c\
29 # url.c 29 # mbox.c
30 libmu_pop_la_SOURCES = \ 30 libmu_pop_la_SOURCES = \
31 \ 31 \
32 pop3_apop.c \ 32 pop3_apop.c \
33 pop3_capa.c \ 33 pop3_capa.c \
34 pop3_capatst.c \
34 pop3_carrier.c \ 35 pop3_carrier.c \
35 pop3_connect.c \ 36 pop3_connect.c \
36 pop3_create.c \ 37 pop3_create.c \
...@@ -39,10 +40,13 @@ libmu_pop_la_SOURCES = \ ...@@ -39,10 +40,13 @@ libmu_pop_la_SOURCES = \
39 pop3_disconnect.c \ 40 pop3_disconnect.c \
40 pop3_iterator.c \ 41 pop3_iterator.c \
41 pop3_lista.c \ 42 pop3_lista.c \
43 pop3_listas.c \
42 pop3_list.c \ 44 pop3_list.c \
45 pop3_list_cmd.c \
43 pop3_noop.c \ 46 pop3_noop.c \
44 pop3_pass.c \ 47 pop3_pass.c \
45 pop3_quit.c \ 48 pop3_quit.c \
49 pop3_rdlist.c \
46 pop3_readline.c \ 50 pop3_readline.c \
47 pop3_response.c \ 51 pop3_response.c \
48 pop3_retr.c \ 52 pop3_retr.c \
...@@ -54,7 +58,9 @@ libmu_pop_la_SOURCES = \ ...@@ -54,7 +58,9 @@ libmu_pop_la_SOURCES = \
54 pop3_timeout.c \ 58 pop3_timeout.c \
55 pop3_top.c \ 59 pop3_top.c \
56 pop3_trace.c \ 60 pop3_trace.c \
61 pop3_uidl_cmd.c \
57 pop3_uidla.c \ 62 pop3_uidla.c \
63 pop3_uidlas.c \
58 pop3_uidl.c \ 64 pop3_uidl.c \
59 pop3_user.c 65 pop3_user.c
60 66
......
...@@ -33,36 +33,18 @@ ...@@ -33,36 +33,18 @@
33 #include <mailutils/sys/pop3.h> 33 #include <mailutils/sys/pop3.h>
34 34
35 static int 35 static int
36 string_comp (const void *item, const void *value) 36 capa_comp (const void *item, const void *value)
37 { 37 {
38 return strcmp (item, value); 38 const char *capa = item;
39 } 39 const char *needle = value;
40 40 for (; *needle; capa++, needle++)
41 int
42 _mu_pop3_fill_list (mu_pop3_t pop3, mu_list_t list)
43 {
44 mu_stream_t stream;
45 size_t n;
46 int status = mu_pop3_stream_create (pop3, &stream);
47 if (status)
48 return status;
49
50 while (mu_stream_getline (stream, &pop3->rdbuf, &pop3->rdsize, &n) == 0
51 && n > 0)
52 { 41 {
53 char *np = strdup (pop3->rdbuf); 42 if (!*capa)
54 if (!np) 43 return 1;
55 { 44 if (mu_tolower (*capa) != mu_tolower (*needle))
56 status = ENOMEM; 45 return 1;
57 break;
58 }
59 mu_rtrim_class (np, MU_CTYPE_SPACE);
60 status = mu_list_append (list, np);
61 if (status)
62 break;
63 } 46 }
64 mu_stream_destroy (&stream); 47 return !(*capa == 0 || mu_isspace (*capa));
65 return status;
66 } 48 }
67 49
68 /* 50 /*
...@@ -91,7 +73,7 @@ mu_pop3_capa (mu_pop3_t pop3, int reread, mu_iterator_t *piter) ...@@ -91,7 +73,7 @@ mu_pop3_capa (mu_pop3_t pop3, int reread, mu_iterator_t *piter)
91 status = mu_list_create (&pop3->capa); 73 status = mu_list_create (&pop3->capa);
92 if (status) 74 if (status)
93 return status; 75 return status;
94 mu_list_set_comparator (pop3->capa, string_comp); 76 mu_list_set_comparator (pop3->capa, capa_comp);
95 mu_list_set_destroy_item (pop3->capa, mu_list_free_item); 77 mu_list_set_destroy_item (pop3->capa, mu_list_free_item);
96 78
97 switch (pop3->state) 79 switch (pop3->state)
...@@ -109,7 +91,7 @@ mu_pop3_capa (mu_pop3_t pop3, int reread, mu_iterator_t *piter) ...@@ -109,7 +91,7 @@ mu_pop3_capa (mu_pop3_t pop3, int reread, mu_iterator_t *piter)
109 pop3->state = MU_POP3_CAPA_RX; 91 pop3->state = MU_POP3_CAPA_RX;
110 92
111 case MU_POP3_CAPA_RX: 93 case MU_POP3_CAPA_RX:
112 status = _mu_pop3_fill_list (pop3, pop3->capa); 94 status = mu_pop3_read_list (pop3, pop3->capa);
113 MU_POP3_CHECK_ERROR (pop3, status); 95 MU_POP3_CHECK_ERROR (pop3, status);
114 if (piter) 96 if (piter)
115 status = mu_list_get_iterator (pop3->capa, piter); 97 status = mu_list_get_iterator (pop3->capa, piter);
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2003, 2004, 2005, 2007, 2010 Free Software Foundation,
3 Inc.
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 3 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General
16 Public License along with this library; if not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301 USA */
19
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
23
24 #include <stdlib.h>
25 #include <mailutils/list.h>
26 #include <mailutils/sys/pop3.h>
27
28 int
29 pop3_capa_test (mu_pop3_t pop3, const char *name, const char **pret)
30 {
31 int rc;
32
33 rc = mu_pop3_capa (pop3, 0, NULL);
34 if (rc)
35 return rc;
36 return mu_list_locate (pop3->capa, (void*) name, (void**)pret);
37 }
...@@ -40,7 +40,7 @@ mu_pop3_list (mu_pop3_t pop3, unsigned int msgno, size_t *psize) ...@@ -40,7 +40,7 @@ mu_pop3_list (mu_pop3_t pop3, unsigned int msgno, size_t *psize)
40 switch (pop3->state) 40 switch (pop3->state)
41 { 41 {
42 case MU_POP3_NO_STATE: 42 case MU_POP3_NO_STATE:
43 status = mu_pop3_writeline (pop3, "LIST %d\r\n", msgno); 43 status = mu_pop3_writeline (pop3, "LIST %u\r\n", msgno);
44 MU_POP3_CHECK_ERROR (pop3, status); 44 MU_POP3_CHECK_ERROR (pop3, status);
45 MU_POP3_FCLR (pop3, MU_POP3_ACK); 45 MU_POP3_FCLR (pop3, MU_POP3_ACK);
46 pop3->state = MU_POP3_LIST; 46 pop3->state = MU_POP3_LIST;
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 1999, 2000, 2001, 2004, 2007, 2010 Free Software
3 Foundation, Inc.
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 3 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General
16 Public License along with this library; if not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301 USA */
19
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
23
24 #include <stdlib.h>
25 #include <mailutils/sys/pop3.h>
26
27 int
28 mu_pop3_list_cmd (mu_pop3_t pop3)
29 {
30 int status = 0;
31
32 if (pop3 == NULL)
33 return EINVAL;
34
35 switch (pop3->state)
36 {
37 case MU_POP3_NO_STATE:
38 status = mu_pop3_writeline (pop3, "LIST\r\n");
39 MU_POP3_CHECK_ERROR (pop3, status);
40 MU_POP3_FCLR (pop3, MU_POP3_ACK);
41 pop3->state = MU_POP3_LIST;
42
43 case MU_POP3_LIST:
44 status = mu_pop3_response (pop3, NULL);
45 MU_POP3_CHECK_EAGAIN (pop3, status);
46 MU_POP3_CHECK_OK (pop3);
47 pop3->state = MU_POP3_LIST_RX;
48
49 case MU_POP3_LIST_RX:
50 /* The mu_iterator_t will read the stream and set the state to
51 MU_POP3_NO_STATE when done. */
52 break;
53
54 /* They must deal with the error first by reopening. */
55 case MU_POP3_ERROR:
56 status = ECANCELED;
57 break;
58
59 default:
60 status = EINPROGRESS;
61 }
62
63 return status;
64 }
...@@ -21,51 +21,19 @@ ...@@ -21,51 +21,19 @@
21 # include <config.h> 21 # include <config.h>
22 #endif 22 #endif
23 23
24 #include <string.h>
25 #include <errno.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <mailutils/sys/pop3.h> 24 #include <mailutils/sys/pop3.h>
29 25
30 int 26 int
31 mu_pop3_list_all (mu_pop3_t pop3, mu_iterator_t *piterator) 27 mu_pop3_list_all (mu_pop3_t pop3, mu_iterator_t *piterator)
32 { 28 {
33 int status = 0; 29 int status = mu_pop3_list_cmd (pop3);
34 30
35 if (pop3 == NULL) 31 if (status)
36 return EINVAL; 32 return status;
37 if (piterator == NULL)
38 return MU_ERR_OUT_PTR_NULL;
39
40 switch (pop3->state)
41 {
42 case MU_POP3_NO_STATE:
43 status = mu_pop3_writeline (pop3, "LIST\r\n");
44 MU_POP3_CHECK_ERROR (pop3, status);
45 MU_POP3_FCLR (pop3, MU_POP3_ACK);
46 pop3->state = MU_POP3_LIST;
47 33
48 case MU_POP3_LIST:
49 status = mu_pop3_response (pop3, NULL);
50 MU_POP3_CHECK_EAGAIN (pop3, status);
51 MU_POP3_CHECK_OK (pop3);
52 status = mu_pop3_iterator_create (pop3, piterator); 34 status = mu_pop3_iterator_create (pop3, piterator);
53 MU_POP3_CHECK_ERROR (pop3, status); 35 MU_POP3_CHECK_ERROR (pop3, status);
54 pop3->state = MU_POP3_LIST_RX; 36 pop3->state = MU_POP3_LIST_RX;
55 37
56 case MU_POP3_LIST_RX:
57 /* The mu_iterator_t will read the stream and set the state to
58 MU_POP3_NO_STATE when done. */
59 break;
60
61 /* They must deal with the error first by reopening. */
62 case MU_POP3_ERROR:
63 status = ECANCELED;
64 break;
65
66 default:
67 status = EINPROGRESS;
68 }
69
70 return status; 38 return status;
71 } 39 }
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 1999, 2000, 2001, 2004, 2007, 2010 Free Software
3 Foundation, Inc.
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 3 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General
16 Public License along with this library; if not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301 USA */
19
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
23
24 #include <mailutils/sys/pop3.h>
25
26 int
27 mu_pop3_list_all_stream (mu_pop3_t pop3, mu_stream_t *pstream)
28 {
29 int status = mu_pop3_list_cmd (pop3);
30
31 if (status)
32 return status;
33
34 status = mu_pop3_stream_create (pop3, pstream);
35 MU_POP3_CHECK_ERROR (pop3, status);
36 pop3->state = MU_POP3_LIST_RX;
37
38 return status;
39 }
1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2003, 2004, 2005, 2007, 2010 Free Software Foundation,
3 Inc.
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 3 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General
16 Public License along with this library; if not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301 USA */
19
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
23
24 #include <string.h>
25 #include <mailutils/stream.h>
26 #include <mailutils/list.h>
27 #include <mailutils/cctype.h>
28 #include <mailutils/cstr.h>
29 #include <mailutils/sys/pop3.h>
30
31 int
32 mu_pop3_stream_to_list (mu_pop3_t pop3, mu_stream_t stream, mu_list_t list)
33 {
34 int status;
35 size_t n;
36
37 while (mu_stream_getline (stream, &pop3->rdbuf, &pop3->rdsize, &n) == 0
38 && n > 0)
39 {
40 char *np = strdup (pop3->rdbuf);
41 if (!np)
42 {
43 status = ENOMEM;
44 break;
45 }
46 mu_rtrim_class (np, MU_CTYPE_SPACE);
47 status = mu_list_append (list, np);
48 if (status)
49 break;
50 }
51 return status;
52 }
53
54 int
55 mu_pop3_read_list (mu_pop3_t pop3, mu_list_t list)
56 {
57 mu_stream_t stream;
58 int status = mu_pop3_stream_create (pop3, &stream);
59 if (status)
60 return status;
61 status = mu_pop3_stream_to_list (pop3, stream, list);
62 mu_stream_destroy (&stream);
63 return status;
64 }
65
...@@ -48,12 +48,11 @@ mu_pop3_retr (mu_pop3_t pop3, unsigned int msgno, mu_stream_t *pstream) ...@@ -48,12 +48,11 @@ mu_pop3_retr (mu_pop3_t pop3, unsigned int msgno, mu_stream_t *pstream)
48 status = mu_pop3_response (pop3, NULL); 48 status = mu_pop3_response (pop3, NULL);
49 MU_POP3_CHECK_EAGAIN (pop3, status); 49 MU_POP3_CHECK_EAGAIN (pop3, status);
50 MU_POP3_CHECK_OK (pop3); 50 MU_POP3_CHECK_OK (pop3);
51 status = mu_pop3_stream_create (pop3, pstream);
52 MU_POP3_CHECK_ERROR (pop3, status);
51 pop3->state = MU_POP3_RETR_RX; 53 pop3->state = MU_POP3_RETR_RX;
52 54
53 case MU_POP3_RETR_RX: 55 case MU_POP3_RETR_RX:
54 status = mu_pop3_stream_create (pop3, pstream);
55 MU_POP3_CHECK_ERROR (pop3, status);
56 pop3->state = MU_POP3_NO_STATE;
57 break; 56 break;
58 57
59 /* They must deal with the error first by reopening. */ 58 /* They must deal with the error first by reopening. */
......
...@@ -39,6 +39,7 @@ struct mu_pop3_stream ...@@ -39,6 +39,7 @@ struct mu_pop3_stream
39 enum pop3_decode_state 39 enum pop3_decode_state
40 { 40 {
41 pds_init, /* initial state */ 41 pds_init, /* initial state */
42 pds_char, /* Any character excepting [\r\n.] */
42 pds_cr, /* prev. char was \r */ 43 pds_cr, /* prev. char was \r */
43 pds_crlf, /* 2 prev. char were \r\n */ 44 pds_crlf, /* 2 prev. char were \r\n */
44 pds_dot, /* 3 prev. chars were \r\n. */ 45 pds_dot, /* 3 prev. chars were \r\n. */
...@@ -56,6 +57,16 @@ newstate (int state, int c) ...@@ -56,6 +57,16 @@ newstate (int state, int c)
56 { 57 {
57 case '\r': 58 case '\r':
58 return pds_cr; 59 return pds_cr;
60 case '.':
61 return pds_dot;
62 }
63 break;
64
65 case pds_char:
66 switch (c)
67 {
68 case '\r':
69 return pds_cr;
59 } 70 }
60 break; 71 break;
61 72
...@@ -93,7 +104,7 @@ newstate (int state, int c) ...@@ -93,7 +104,7 @@ newstate (int state, int c)
93 return pds_end; 104 return pds_end;
94 } 105 }
95 } 106 }
96 return pds_init; 107 return pds_char;
97 } 108 }
98 109
99 /* Move min(isize,osize) bytes from iptr to optr, replacing each \r\n 110 /* Move min(isize,osize) bytes from iptr to optr, replacing each \r\n
...@@ -140,7 +151,7 @@ _pop3_decoder (void *xd, ...@@ -140,7 +151,7 @@ _pop3_decoder (void *xd,
140 if (*iptr == '\n') 151 if (*iptr == '\n')
141 continue; 152 continue;
142 } 153 }
143 else if (c == '.' && *pstate == pds_crlf) 154 else if (c == '.' && (*pstate == pds_init || *pstate == pds_crlf))
144 { 155 {
145 /* Make sure we have two more characters in the buffer */ 156 /* Make sure we have two more characters in the buffer */
146 if (i + 2 == isize) 157 if (i + 2 == isize)
...@@ -164,16 +175,39 @@ _pop3_decoder (void *xd, ...@@ -164,16 +175,39 @@ _pop3_decoder (void *xd,
164 return mu_filter_ok; 175 return mu_filter_ok;
165 } 176 }
166 177
178 static void
179 _pop3_event_cb (mu_stream_t str, int ev, int flags)
180 {
181 if (ev == _MU_STR_EVENT_SET)
182 {
183 mu_transport_t trans[2];
184
185 if (mu_stream_ioctl (str, MU_IOCTL_GET_TRANSPORT, trans) == 0)
186 {
187 struct mu_pop3_stream *sp = (struct mu_pop3_stream *) trans[0];
188 sp->pop3->state = MU_POP3_NO_STATE;
189 }
190 }
191 }
192
167 static int 193 static int
168 mu_pop3_filter_create (mu_stream_t *pstream, mu_stream_t stream) 194 mu_pop3_filter_create (mu_stream_t *pstream, mu_stream_t stream)
169 { 195 {
196 int rc;
170 int *state = malloc (sizeof (*state)); 197 int *state = malloc (sizeof (*state));
171 if (!state) 198 if (!state)
172 return ENOMEM; 199 return ENOMEM;
173 return mu_filter_stream_create (pstream, stream, 200 rc = mu_filter_stream_create (pstream, stream,
174 MU_FILTER_DECODE, 201 MU_FILTER_DECODE,
175 _pop3_decoder, state, 202 _pop3_decoder, state,
176 MU_STREAM_READ); 203 MU_STREAM_READ);
204 if (rc == 0)
205 {
206 mu_stream_t str = *pstream;
207 str->event_cb = _pop3_event_cb;
208 str->event_mask = _MU_STR_EOF;
209 }
210 return rc;
177 } 211 }
178 212
179 213
...@@ -257,6 +291,7 @@ mu_pop3_stream_create (mu_pop3_t pop3, mu_stream_t *pstream) ...@@ -257,6 +291,7 @@ mu_pop3_stream_create (mu_pop3_t pop3, mu_stream_t *pstream)
257 sp->stream.readdelim = _mu_pop3_readdelim; 291 sp->stream.readdelim = _mu_pop3_readdelim;
258 sp->stream.flush = _mu_pop3_flush; 292 sp->stream.flush = _mu_pop3_flush;
259 sp->stream.wait = _mu_pop3_wait; 293 sp->stream.wait = _mu_pop3_wait;
294
260 sp->pop3 = pop3; 295 sp->pop3 = pop3;
261 sp->done = 0; 296 sp->done = 0;
262 str = (mu_stream_t) sp; 297 str = (mu_stream_t) sp;
......
...@@ -48,12 +48,11 @@ mu_pop3_top (mu_pop3_t pop3, unsigned msgno, unsigned int lines, ...@@ -48,12 +48,11 @@ mu_pop3_top (mu_pop3_t pop3, unsigned msgno, unsigned int lines,
48 status = mu_pop3_response (pop3, NULL); 48 status = mu_pop3_response (pop3, NULL);
49 MU_POP3_CHECK_EAGAIN (pop3, status); 49 MU_POP3_CHECK_EAGAIN (pop3, status);
50 MU_POP3_CHECK_OK (pop3); 50 MU_POP3_CHECK_OK (pop3);
51 status = mu_pop3_stream_create (pop3, pstream);
52 MU_POP3_CHECK_ERROR (pop3, status);
51 pop3->state = MU_POP3_TOP_RX; 53 pop3->state = MU_POP3_TOP_RX;
52 54
53 case MU_POP3_TOP_RX: 55 case MU_POP3_TOP_RX:
54 status = mu_pop3_stream_create (pop3, pstream);
55 MU_POP3_CHECK_ERROR (pop3, status);
56 pop3->state = MU_POP3_NO_STATE;
57 break; 56 break;
58 57
59 /* They must deal with the error first by reopening. */ 58 /* They must deal with the error first by reopening. */
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2003, 2004, 2007, 2010 Free Software Foundation, Inc.
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 3 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General
15 Public License along with this library; if not, write to the
16 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 Boston, MA 02110-1301 USA */
18
19 #ifdef HAVE_CONFIG_H
20 # include <config.h>
21 #endif
22
23 #include <stdlib.h>
24 #include <mailutils/sys/pop3.h>
25
26 int
27 mu_pop3_uidl_all_cmd (mu_pop3_t pop3)
28 {
29 int status = 0;
30
31 if (pop3 == NULL)
32 return EINVAL;
33
34 switch (pop3->state)
35 {
36 case MU_POP3_NO_STATE:
37 status = mu_pop3_writeline (pop3, "UIDL\r\n");
38 MU_POP3_CHECK_ERROR (pop3, status);
39 MU_POP3_FCLR (pop3, MU_POP3_ACK);
40 pop3->state = MU_POP3_UIDL;
41
42 case MU_POP3_UIDL:
43 status = mu_pop3_response (pop3, NULL);
44 MU_POP3_CHECK_EAGAIN (pop3, status);
45 MU_POP3_CHECK_OK (pop3);
46 pop3->state = MU_POP3_UIDL_RX;
47
48 case MU_POP3_UIDL_RX:
49 break;
50
51 /* They must deal with the error first by reopening. */
52 case MU_POP3_ERROR:
53 status = ECANCELED;
54 break;
55
56 default:
57 status = EINPROGRESS;
58 }
59
60 return status;
61 }
...@@ -20,50 +20,17 @@ ...@@ -20,50 +20,17 @@
20 # include <config.h> 20 # include <config.h>
21 #endif 21 #endif
22 22
23 #include <string.h>
24 # include <errno.h>
25 #include <stdlib.h>
26 #include <mailutils/sys/pop3.h> 23 #include <mailutils/sys/pop3.h>
27 24
28 int 25 int
29 mu_pop3_uidl_all (mu_pop3_t pop3, mu_iterator_t *piterator) 26 mu_pop3_uidl_all (mu_pop3_t pop3, mu_iterator_t *piterator)
30 { 27 {
31 int status = 0; 28 int status = mu_pop3_uidl_all_cmd (pop3);
32 29 if (status)
33 if (pop3 == NULL) 30 return status;
34 return EINVAL;
35 if (piterator == NULL)
36 return MU_ERR_OUT_PTR_NULL;
37
38 switch (pop3->state)
39 {
40 case MU_POP3_NO_STATE:
41 status = mu_pop3_writeline (pop3, "UIDL\r\n");
42 MU_POP3_CHECK_ERROR (pop3, status);
43 MU_POP3_FCLR (pop3, MU_POP3_ACK);
44 pop3->state = MU_POP3_UIDL;
45
46 case MU_POP3_UIDL:
47 status = mu_pop3_response (pop3, NULL);
48 MU_POP3_CHECK_EAGAIN (pop3, status);
49 MU_POP3_CHECK_OK (pop3);
50 status = mu_pop3_iterator_create (pop3, piterator); 31 status = mu_pop3_iterator_create (pop3, piterator);
51 MU_POP3_CHECK_ERROR (pop3, status); 32 MU_POP3_CHECK_ERROR (pop3, status);
52 pop3->state = MU_POP3_UIDL_RX; 33 pop3->state = MU_POP3_UIDL_RX;
53 34
54 case MU_POP3_UIDL_RX:
55 /* The mu_iterator_t will read the stream and set the state to
56 MU_POP3_NO_STATE when done. */
57 break;
58
59 /* They must deal with the error first by reopening. */
60 case MU_POP3_ERROR:
61 status = ECANCELED;
62 break;
63
64 default:
65 status = EINPROGRESS;
66 }
67
68 return status; 35 return status;
69 } 36 }
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2003, 2004, 2007, 2010 Free Software Foundation, Inc.
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 3 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General
15 Public License along with this library; if not, write to the
16 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 Boston, MA 02110-1301 USA */
18
19 #ifdef HAVE_CONFIG_H
20 # include <config.h>
21 #endif
22
23 #include <mailutils/sys/pop3.h>
24
25 int
26 mu_pop3_uidl_all_stream (mu_pop3_t pop3, mu_stream_t *pstream)
27 {
28 int status = mu_pop3_uidl_all_cmd (pop3);
29 if (status)
30 return status;
31 status = mu_pop3_stream_create (pop3, pstream);
32 MU_POP3_CHECK_ERROR (pop3, status);
33 pop3->state = MU_POP3_UIDL_RX;
34
35 return status;
36 }
...@@ -164,7 +164,7 @@ filter_read (mu_stream_t stream, char *buf, size_t size, size_t *pret) ...@@ -164,7 +164,7 @@ filter_read (mu_stream_t stream, char *buf, size_t size, size_t *pret)
164 return MU_ERR_FAILURE; /* FIXME: special error code? */ 164 return MU_ERR_FAILURE; /* FIXME: special error code? */
165 if (iobuf.eof) 165 if (iobuf.eof)
166 { 166 {
167 stream->flags |= _MU_STR_EOF; 167 _mu_stream_seteof (stream);
168 stop = 1; 168 stop = 1;
169 } 169 }
170 break; 170 break;
......
...@@ -32,6 +32,22 @@ ...@@ -32,6 +32,22 @@
32 #include <mailutils/stream.h> 32 #include <mailutils/stream.h>
33 #include <mailutils/sys/stream.h> 33 #include <mailutils/sys/stream.h>
34 34
35 static void
36 _stream_setflag (struct _mu_stream *stream, int flag)
37 {
38 if (stream->event_cb && (stream->event_mask & flag))
39 stream->event_cb (stream, _MU_STR_EVENT_SET, flag);
40 stream->flags |= flag;
41 }
42
43 static void
44 _stream_clrflag (struct _mu_stream *stream, int flag)
45 {
46 if (stream->event_cb && (stream->event_mask & flag))
47 stream->event_cb (stream, _MU_STR_EVENT_CLR, flag);
48 stream->flags &= ~flag;
49 }
50
35 int 51 int
36 mu_stream_seterr (struct _mu_stream *stream, int code, int perm) 52 mu_stream_seterr (struct _mu_stream *stream, int code, int perm)
37 { 53 {
...@@ -45,12 +61,23 @@ mu_stream_seterr (struct _mu_stream *stream, int code, int perm) ...@@ -45,12 +61,23 @@ mu_stream_seterr (struct _mu_stream *stream, int code, int perm)
45 61
46 default: 62 default:
47 if (perm) 63 if (perm)
48 stream->flags |= _MU_STR_ERR; 64 _stream_setflag (stream, _MU_STR_ERR);
49 } 65 }
50 return code; 66 return code;
51 } 67 }
52 68
53 #define _stream_cleareof(s) ((s)->flags &= ~_MU_STR_EOF) 69 void
70 _mu_stream_cleareof (mu_stream_t str)
71 {
72 _stream_clrflag (str, _MU_STR_EOF);
73 }
74
75 void
76 _mu_stream_seteof (mu_stream_t str)
77 {
78 _stream_setflag (str, _MU_STR_EOF);
79 }
80
54 #define _stream_advance_buffer(s,n) ((s)->cur += n, (s)->level -= n) 81 #define _stream_advance_buffer(s,n) ((s)->cur += n, (s)->level -= n)
55 #define _stream_buffer_offset(s) ((s)->cur - (s)->buffer) 82 #define _stream_buffer_offset(s) ((s)->cur - (s)->buffer)
56 #define _stream_orig_level(s) ((s)->level + _stream_buffer_offset (s)) 83 #define _stream_orig_level(s) ((s)->level + _stream_buffer_offset (s))
...@@ -82,9 +109,13 @@ _stream_fill_buffer (struct _mu_stream *stream) ...@@ -82,9 +109,13 @@ _stream_fill_buffer (struct _mu_stream *stream)
82 for (n = 0; 109 for (n = 0;
83 n < stream->bufsize 110 n < stream->bufsize
84 && (rc = mu_stream_read_unbuffered (stream, 111 && (rc = mu_stream_read_unbuffered (stream,
85 &c, 1, 0, &rdn)) == 0 112 &c, 1, 0, &rdn)) == 0;)
86 && rdn; ) 113 {
114 if (rdn == 0)
87 { 115 {
116 _stream_setflag (stream, _MU_STR_EOF);
117 break;
118 }
88 stream->buffer[n++] = c; 119 stream->buffer[n++] = c;
89 if (c == '\n') 120 if (c == '\n')
90 break; 121 break;
...@@ -175,7 +206,7 @@ _stream_flush_buffer (struct _mu_stream *stream, int all) ...@@ -175,7 +206,7 @@ _stream_flush_buffer (struct _mu_stream *stream, int all)
175 } 206 }
176 else 207 else
177 { 208 {
178 stream->flags &= ~_MU_STR_DIRTY; 209 _stream_clrflag (stream, _MU_STR_DIRTY);
179 stream->level = 0; 210 stream->level = 0;
180 } 211 }
181 stream->cur = stream->buffer; 212 stream->cur = stream->buffer;
...@@ -269,7 +300,7 @@ void ...@@ -269,7 +300,7 @@ void
269 mu_stream_clearerr (mu_stream_t stream) 300 mu_stream_clearerr (mu_stream_t stream)
270 { 301 {
271 stream->last_err = 0; 302 stream->last_err = 0;
272 stream->flags &= ~_MU_STR_ERR; 303 _stream_clrflag (stream, _MU_STR_ERR);
273 } 304 }
274 305
275 int 306 int
...@@ -327,7 +358,7 @@ mu_stream_seek (mu_stream_t stream, mu_off_t offset, int whence, ...@@ -327,7 +358,7 @@ mu_stream_seek (mu_stream_t stream, mu_off_t offset, int whence,
327 return rc; 358 return rc;
328 if (rc) 359 if (rc)
329 return mu_stream_seterr (stream, rc, 1); 360 return mu_stream_seterr (stream, rc, 1);
330 _stream_cleareof (stream); 361 _mu_stream_cleareof (stream);
331 } 362 }
332 363
333 if (pres) 364 if (pres)
...@@ -469,7 +500,7 @@ mu_stream_read_unbuffered (mu_stream_t stream, void *buf, size_t size, ...@@ -469,7 +500,7 @@ mu_stream_read_unbuffered (mu_stream_t stream, void *buf, size_t size,
469 { 500 {
470 if (rdbytes == 0) 501 if (rdbytes == 0)
471 { 502 {
472 stream->flags |= _MU_STR_EOF; 503 _stream_setflag (stream, _MU_STR_EOF);
473 break; 504 break;
474 } 505 }
475 buf += rdbytes; 506 buf += rdbytes;
...@@ -487,7 +518,7 @@ mu_stream_read_unbuffered (mu_stream_t stream, void *buf, size_t size, ...@@ -487,7 +518,7 @@ mu_stream_read_unbuffered (mu_stream_t stream, void *buf, size_t size,
487 if (rc == 0) 518 if (rc == 0)
488 { 519 {
489 if (nread == 0) 520 if (nread == 0)
490 stream->flags |= _MU_STR_EOF; 521 _stream_setflag (stream, _MU_STR_EOF);
491 stream->bytes_in += nread; 522 stream->bytes_in += nread;
492 } 523 }
493 mu_stream_seterr (stream, rc, rc != 0); 524 mu_stream_seterr (stream, rc, rc != 0);
...@@ -551,7 +582,7 @@ mu_stream_write_unbuffered (mu_stream_t stream, ...@@ -551,7 +582,7 @@ mu_stream_write_unbuffered (mu_stream_t stream,
551 if (rc == 0) 582 if (rc == 0)
552 stream->bytes_out += nwritten; 583 stream->bytes_out += nwritten;
553 } 584 }
554 stream->flags |= _MU_STR_WRT; 585 _stream_setflag (stream, _MU_STR_WRT);
555 stream->offset += nwritten; 586 stream->offset += nwritten;
556 if (pnwritten) 587 if (pnwritten)
557 *pnwritten = nwritten; 588 *pnwritten = nwritten;
...@@ -806,7 +837,7 @@ mu_stream_write (mu_stream_t stream, const void *buf, size_t size, ...@@ -806,7 +837,7 @@ mu_stream_write (mu_stream_t stream, const void *buf, size_t size,
806 nbytes += n; 837 nbytes += n;
807 bufp += n; 838 bufp += n;
808 size -= n; 839 size -= n;
809 stream->flags |= _MU_STR_DIRTY; 840 _stream_setflag (stream, _MU_STR_DIRTY);
810 } 841 }
811 if (pnwritten) 842 if (pnwritten)
812 *pnwritten = nbytes; 843 *pnwritten = nbytes;
...@@ -835,7 +866,7 @@ mu_stream_flush (mu_stream_t stream) ...@@ -835,7 +866,7 @@ mu_stream_flush (mu_stream_t stream)
835 return rc; 866 return rc;
836 if ((stream->flags & _MU_STR_WRT) && stream->flush) 867 if ((stream->flags & _MU_STR_WRT) && stream->flush)
837 return stream->flush (stream); 868 return stream->flush (stream);
838 stream->flags &= ~_MU_STR_WRT; 869 _stream_clrflag (stream, _MU_STR_WRT);
839 return 0; 870 return 0;
840 } 871 }
841 872
......