* imap4d/create.c: First implementation.
* imap4d/delete.c: First implementation. * imap4d/list.c: First implementation. * imap4d/rename.c: First implementation. * imap4d/util.c: New functions. (util_tilde_expansion): expand ~. (util_unquote): Remove surrounding double quotes. (util_getfullpath): Expand the path to absolute. * imap4d/fetch.c: Did not cycle throught the items. (fetch_send_address): Patch from Sam Roberts, did not use the index. * mailbox/attachement.c (message_unencapsulate): Little buglet strncasemp() passing the wrong size.
Showing
10 changed files
with
926 additions
and
172 deletions
1 | 2001-04-22 Alain Magloire | ||
2 | |||
3 | * imap4d/create.c: First implementation. | ||
4 | * imap4d/delete.c: First implementation. | ||
5 | * imap4d/list.c: First implementation. | ||
6 | * imap4d/rename.c: First implementation. | ||
7 | * imap4d/util.c: New functions. | ||
8 | (util_tilde_expansion): expand ~. | ||
9 | (util_unquote): Remove surrounding double quotes. | ||
10 | (util_getfullpath): Expand the path to absolute. | ||
11 | * imap4d/fetch.c: Did not cycle throught the items. | ||
12 | (fetch_send_address): Patch from Sam Roberts, did not | ||
13 | use the index. | ||
14 | |||
15 | * mailbox/attachement.c (message_unencapsulate): Little buglet | ||
16 | strncasemp() passing the wrong size. | ||
17 | |||
1 | 2001-04-19 Alain Magloire | 18 | 2001-04-19 Alain Magloire |
2 | 19 | ||
3 | * mailbox/smtp.c(smtp_readline): Because of the buffering mechanism, | 20 | * mailbox/smtp.c(smtp_readline): Because of the buffering mechanism, |
... | @@ -332,6 +349,339 @@ | ... | @@ -332,6 +349,339 @@ |
332 | This feature was put in to help the imap4d server, in this protocol | 349 | This feature was put in to help the imap4d server, in this protocol |
333 | you can get a substring of the message starting from a certain offset. | 350 | you can get a substring of the message starting from a certain offset. |
334 | To make the coding of imap4d simpler the complexity was move to the | 351 | To make the coding of imap4d simpler the complexity was move to the |
352 | |||
353 | * mailbox/smtp.c(smtp_readline): Because of the buffering mechanism, | ||
354 | we must maintain the offset. | ||
355 | |||
356 | * imap4d/list.c: partially implemented the LIST command. | ||
357 | * imap4d/imap4d.c: homedir new global variable. | ||
358 | * imap4d/login.c: same ${HOME} in homedir. | ||
359 | * imap4d/util.c (util_getword): Be aware of the quotes. | ||
360 | |||
361 | * lib/fnmatch.c: New replacement file. | ||
362 | * lib/fnmatch.h: New replacement file. | ||
363 | * configure.in: Check for fnmatch(). | ||
364 | |||
365 | 2001-04-18 Alain Magloire | ||
366 | |||
367 | Finally took time to put the code in from Jakob first draft, in | ||
368 | an email excerpt: | ||
369 | states is the valid states for a command (eg. LOGIN is only valid in | ||
370 | non-authenticated state, SELECT is valid in authenticated or | ||
371 | selected). success is the state to enter when the command completes | ||
372 | successfully (STATE_NONE means no change) and failure is the state to | ||
373 | enter when the command fails. | ||
374 | |||
375 | * imap4d/*.c: All the commands check there state. | ||
376 | * imap4d/fetch.c: Cleanup the fetch code, and broke | ||
377 | the fetch_operation() routine in multiple routines. | ||
378 | (fetch_message): New function. | ||
379 | (fetch_header): Likewised | ||
380 | (fetch_content): Likewised | ||
381 | (fetch_io): Likewised | ||
382 | (fetch_header_fields): Likewised | ||
383 | (fetch_header_fields_not): Likewised | ||
384 | (fetch_send_address): Likewised | ||
385 | |||
386 | * mailbox/header.c: Some functions were usefull while | ||
387 | programming the imap server, put them here. | ||
388 | (header_aget_value): New function. | ||
389 | (header_aget_field_name): New function. | ||
390 | (header_aget_field_value): New function. | ||
391 | |||
392 | * mailbox/memory_stream.c: New file, implemented a | ||
393 | malloc() buffer that you can access via the stream interface. | ||
394 | * mailbox/file_stream.c: Remove spurious checks. | ||
395 | * mailbox/mapfile_stream.c: Remove spurious checks. | ||
396 | (_mapfile_read): check if there is no newline left. | ||
397 | |||
398 | 2001-04-16 Alain Magloire | ||
399 | |||
400 | To get things to compile on Solaris, change configure to check | ||
401 | for -lpthread since in libc the thread functions are defined | ||
402 | but all return ENOSYS, you need to explicitely link with -lphtread. | ||
403 | the ctype functions is*() arguments should be explicitely cast | ||
404 | since Solaris use them as indexes. __REENTRANT as to be define | ||
405 | if compile with support for threads. Never realize this but | ||
406 | setenv() is a BSD/GNU thing, so took a variant from libiberty | ||
407 | to cope. | ||
408 | |||
409 | * configure.in: Check for setenv. First check if -lphtread is ok. | ||
410 | * lib/setenv.c: New functions. | ||
411 | * lib/Makefile.am: add setenv.c in EXTRA_DIST. | ||
412 | * imap4d/imap4d.h: Include <alloca.h> | ||
413 | * mailbox/attachment.c: Include <alloca.h> | ||
414 | * (_header_get_param): isspace() cast argument. | ||
415 | * mail/mail.h: check if <paths.h> is available if not | ||
416 | define _PATH_SENDMAIL=/usr/lib/sendmail. | ||
417 | * mailbox/folder_imap.c: if pthread available, define _REENTRANT. | ||
418 | Include <alloca.h>. | ||
419 | (imap_bodystructure0): isdigit() cast argument. | ||
420 | * mailbox/mbx_mbox.c: if pthread available, define _REENTRANT. | ||
421 | Include <alloca.h>. | ||
422 | * mailbox/parse822.c: isdigit() cast argument unsigned. | ||
423 | |||
424 | 2001-04-15 Alain Magloire | ||
425 | |||
426 | The FILE* stream "stdout" is not an lvalue so it is an error to | ||
427 | attempt to assign to it. To be able to redirect at will stdout | ||
428 | we need to assign it. In GNU lib C, it was not error since stdout | ||
429 | stderr, and stdin are variables, but to be portable we can not | ||
430 | assume this. The way out is to always use fprintf () and have | ||
431 | a global varialbe "ofile" pointing to stdout. | ||
432 | |||
433 | * mail/*: All the files under mail been change to use fprintf() | ||
434 | and ofile as the default stdout. | ||
435 | Copyright updated. | ||
436 | |||
437 | 2001-04-15 Alain Magloire | ||
438 | |||
439 | Create a argp directory, it contains the necessary | ||
440 | files to build a standalone libargp.a | ||
441 | |||
442 | * argp: New directory. | ||
443 | argp-ba.c, argp-eexst.c, argp-fmtstream.c, argp-fmtstream.h | ||
444 | argp-fs-xinl.c, argp-help.c, argp-namefrob.h, argp-parse.c | ||
445 | argp-pv.c, argp-pvh.c, argp-xinl.c, argp.h, pin.c. | ||
446 | |||
447 | * mail/mail.c: Comment out the code that use readline | ||
448 | specifics WITH_READLINE. | ||
449 | * mail/mail.h: Likewised. | ||
450 | * mail/util.c: Likewised. | ||
451 | |||
452 | 2001-04-15 Alain Magloire | ||
453 | |||
454 | * Makefile.am: Add argp in the list of subdirs. | ||
455 | * configure.am: Check for argp.h and look for | ||
456 | argp_parse(). | ||
457 | * lib/strchrnul.c: New function. | ||
458 | * lib/strndup.c: New function. | ||
459 | * lib/strnlen.c: New function. | ||
460 | * lib/vasnprintf.c: New function. | ||
461 | * lib/getopt.c: Updated. | ||
462 | * lib/getopt1.c: Updated. | ||
463 | * lib/getopt.h: Updated. | ||
464 | * frm/Makefile.am: Remove -DTESTING in CFLAGS. | ||
465 | * from/Makefile.am: Remove -DTESTING in CFLAGS. | ||
466 | Add AUTOMAKE_OPTIONS. | ||
467 | * imapd/Makefile.am: Likewised. | ||
468 | * pop3d/Makefile.am: Likewised. | ||
469 | * mail/Makefile.am: Likewised. Added ARGPLIB macro | ||
470 | |||
471 | 2001-04-14 Sam Roberts | ||
472 | * examples/{Makefile,Addrs,addr.c,Addrs.good}: address test f/w. | ||
473 | * include/mailutils/address.h,mailbox/{address.c,parse822.c}: now | ||
474 | stuff a group name into an _address, and added a function to do | ||
475 | a quick check if it is a group. | ||
476 | * mailbox/parse822.c: fixed bug where ",sam@foo.bar" wasn't valid. | ||
477 | |||
478 | 2001-04-14 Alain Magloire | ||
479 | |||
480 | * mailbox/folder_imap.c: When calling imap_writeline () the | ||
481 | cookie for the tag should be unsigned %d --> %u. | ||
482 | (imap_send) : The number of bytes in memmove was wrong. | ||
483 | * mailbox/mbx_imap.c: Some duplicate degug calls MAILBOX_DEBUG0() | ||
484 | removed. | ||
485 | (attribute_string): IMAP does not have a \\Read flag it should be | ||
486 | the same as \\Seen so attribute_read() == attribute_seen(). | ||
487 | (flag_string): New function. | ||
488 | (imap_attr_set_flags): Use flag_string(), instead. | ||
489 | * mailbox/include/imap0.h: CLEAR_STATE() should also deselect | ||
490 | the current mailbox. | ||
491 | |||
492 | * mailbox/mbx_pop.c (pop_write): The number of bytes in the memmove | ||
493 | was wrong. | ||
494 | |||
495 | * imap4d/imap4d.h: Add HAVE_SECURITY_PAM_APPL_H. | ||
496 | * imap4d/login.c: PAM_ERROR wrongly define. | ||
497 | * imap4d/expunge.c: Initialise variable sp. | ||
498 | * imap4d/logout.c: Initialise variable sp. | ||
499 | * imap4d/noop.c: Initialise variable sp. | ||
500 | |||
501 | * mailbox/attachement.c (message_create_attachment): Use base_name(). | ||
502 | * mailbox/mbx_mbox.c (mbox_tmpfile): Use base_name(). | ||
503 | * configure.in: AC_REP_FUNC(vasprintf strcasecmp strncasecmp). | ||
504 | * include/mailutils/Makefile.am: Add property.h, parse822.h. | ||
505 | * lib/vasprintf.c: Taken from libit. | ||
506 | * lib/basename.c: Taken from libit/fileutils. | ||
507 | * lib/Makefile.am.c: Always use our basename(base_name). | ||
508 | (AM_INIT_AUTOMAKE): Change version to 0.0.9 | ||
509 | |||
510 | 2001-04-13 Sam Roberts | ||
511 | |||
512 | QNX needed to include <strings.h> for many of the useful string | ||
513 | functions also to define _QNX_SOURCE so <sys/time.h> doesn't have | ||
514 | an internal warning. | ||
515 | |||
516 | * configure.in: Check for libgen.h. | ||
517 | * imap4d/imap4d.h: Define __QNX_SOURCE. | ||
518 | * mailbox/mime.c: wasn't including config.h | ||
519 | * mailbox/attachment.c: QNX needed libgen.h for basename(), | ||
520 | include <strings.h> if define. | ||
521 | * mailbox/filter.c: Include <strings.h>. | ||
522 | * mailbox/mbx_mbox.c: Include <strings.h>. | ||
523 | * mailbox/folder_imap.c: Include <strings.h>. | ||
524 | * mailbox/header.c: Include <strings.h>. | ||
525 | * mailbox/property.c: Include <strings.h>. | ||
526 | * mailbox/registrar.c: Include <strings.h>. | ||
527 | * mailbox/url.c: Include <strings.h>. | ||
528 | * mailbox/url_pop.c: Include <strings.h>. | ||
529 | * pop3d/user.c: QNX says getspnam(char* n), I cast away the error. | ||
530 | |||
531 | 2001-04-13 Sam Roberts | ||
532 | |||
533 | * mailbox/parse822.c, include/mailutils/parse822.h: now can | ||
534 | quote the local-part of and addr-spec, and a string. | ||
535 | |||
536 | 2001-04-13 Sam Roberts | ||
537 | |||
538 | * doc/address.texi: updated docs, now they match the parse822. | ||
539 | * mailbox/parse822.c: small tweaks to the new parser, the changes | ||
540 | made during the tidying over the last month were: | ||
541 | - use C comments only. | ||
542 | - don't use C++ reserved words. | ||
543 | - fix is_digit() to be like the other is functions | ||
544 | - Changed return codes to: | ||
545 | . no mem (ENOMEM) | ||
546 | . function wasn't called correctly, usually a missing | ||
547 | argument (EINVAL) | ||
548 | . invalid syntax found during parsing (ENOENT) | ||
549 | . success == 0 | ||
550 | - const-corrected the APIs | ||
551 | - removed unnecessary (in C) casts. | ||
552 | - mailbox_t* removed in favor of address_t. | ||
553 | - fix handful of memory leaks detected by Alain. | ||
554 | |||
555 | 2001-04-10 Alain Magloire | ||
556 | |||
557 | * pop3d/retr.c (pop3_retr): Typo. | ||
558 | * pop3d/top.c (pop3_top): No need to reallocate when sending the | ||
559 | headers. | ||
560 | * doc/mailbox.texi: Put the functions in alphabetic orders. | ||
561 | |||
562 | 2001-04-10 Alain Magloire | ||
563 | |||
564 | * mailbox/Makefile.am: filter_trans.c added, trans_stream.c deleted. | ||
565 | * mailbox/attachment.c (message_create_attachment): use | ||
566 | filter_create(). | ||
567 | (message_save_attachment): use filter_create(). | ||
568 | * mailbox/body.c (body_set_lines): Wrong comparison for the owner. | ||
569 | * mailbox/mbx_mbox.c: Do not count the line separtor of part | ||
570 | of the mailbox. | ||
571 | |||
572 | * mailbox/url.c (url_is_same_sheme): New function. | ||
573 | (url_is_same_user): New function. | ||
574 | (url_is_same_path): New function. | ||
575 | (url_is_same_host): New function. | ||
576 | (url_is_same_port): New function. | ||
577 | * mailbox/folder.c : Moved the is_same_*() functions in url.c | ||
578 | they can be generally usefull. | ||
579 | (is_same_sheme): Removed. | ||
580 | (is_same_user): Removed. | ||
581 | (is_same_path): Removed. | ||
582 | (is_same_host): Removed. | ||
583 | (is_same_port): Removed. | ||
584 | |||
585 | * mailbox/folder_imap.c (folder_imap_create): New function, | ||
586 | CREATE a new mailbox. | ||
587 | (folder_imap_open): Calls folder_imap_create when the MU_STREAM_CREAT | ||
588 | flag is set. | ||
589 | * mailbox/mbx_imap.c: Appending messages implemented, if the message | ||
590 | comes from the same imap folder, it is COPY otherwise APPEND. | ||
591 | (is_same_folder): New function. | ||
592 | (imap_append_message): Implemented. | ||
593 | (attribute_string): New functions. | ||
594 | (imap_copy_message): New function. | ||
595 | * mailbox/include/imap0.h: New enum, IMAP_APPEND, IMAP_APPEND_ACK, | ||
596 | IMAP_APPEND_CONT, IMAP_APPEND_SEND, IMAP_COPY, IMAP_COPY_ACK, | ||
597 | IMAP_CREATE, IMAP_CREATE_ACK. | ||
598 | |||
599 | 2001-04-06 Alain Magloire | ||
600 | |||
601 | * mailbox/parse822.c: New parser. | ||
602 | * include/mailutils/parse822.h: New file. | ||
603 | * mailbox/address.c (address_create): Remove the old parsing and use | ||
604 | parse822 as the underlying engine. | ||
605 | (address_parse): Removed. | ||
606 | (gettoken): Removed. | ||
607 | (quotes): Removed. | ||
608 | (address_get_personal): Remove the code to unquote, parse822 takes | ||
609 | care if it. Return value when no field is ENOENT. | ||
610 | (address_get_comments): Return value when no field ENOENT. | ||
611 | (address_get_local_part): Return value when no field ENOENT. | ||
612 | (address_get_domain): Return value when no field ENOENT. | ||
613 | (address_get_email): Return value when no field ENOENT. | ||
614 | (address_get_route): Return value when no field ENOENT. | ||
615 | * mailbox/message.c (message_sender): Use parse822 to retrieve | ||
616 | the email from the From: field. | ||
617 | (message_set_mailbox): New function. | ||
618 | * mailbox/misc.c : Removed the old parsing code. | ||
619 | (gettoken): Removed. | ||
620 | (parseaddr): Removed. | ||
621 | * mailbox/include/misc.h : Removed parseaddr() prototypes. | ||
622 | From Sam Roberts, the new parse822 parser.. | ||
623 | |||
624 | 2001-04-04 Alain Magloire | ||
625 | |||
626 | Introduction of the notion of filter_t object takes a stream and | ||
627 | perform some filtering on it. All the decoding streams will move | ||
628 | to this i.e. quoted-printable, base64 etc .. This scheme will also | ||
629 | permit users to add to the list new filters. Still work in progress. | ||
630 | |||
631 | * mailbox/Makefile.am : Add filter.c filter_rfc822.c. | ||
632 | * mailbox/body.c : When creating a floating body i.e creating | ||
633 | a temporary file, the stream was not "own" by the body_t. | ||
634 | (_body_get_fd): Likewised. | ||
635 | (_body_read):_ Likewised. | ||
636 | (_body_readline): Likewised. | ||
637 | (_body_write): Likewised. | ||
638 | (_body_truncate): Likewised. | ||
639 | (_body_size): Likewised. | ||
640 | (_body_flush): Likewised. | ||
641 | |||
642 | * mailbox/folder_imap.c (imap_literal_string): Check if the | ||
643 | callback.buffer is NULL. | ||
644 | (imap_body): Do no set the callback.type if "FIELDS" is part of the | ||
645 | string. | ||
646 | |||
647 | * mailbox/header.c: Remove the support for RFC822 it will be part | ||
648 | of the filter_t object. | ||
649 | * mailbox/mbx_mbox.c: Likewised. | ||
650 | * mailbox/mailbox.c (mailbox_size): Rename to mailbox_get_size(). | ||
651 | |||
652 | * mailbox/stream.c (stream_is_seekable): New function. | ||
653 | (stream_set_property): New function. | ||
654 | (stream_get_property): New function. | ||
655 | |||
656 | * mailbox/trans_stream.c: Beautify. | ||
657 | |||
658 | * include/mailutils/filter.h: new file. | ||
659 | |||
660 | * doc/mailbox.texi: Updated. | ||
661 | More changes to come. | ||
662 | |||
663 | 2001-03-20 Alain Magloire | ||
664 | |||
665 | * mailbox/folder_imap.c (imap_readline) : If the server goes away | ||
666 | suddenly return an error. | ||
667 | * mailbox/smtp.c (smtp_readline) : If the server goes away | ||
668 | suddenly return an error. | ||
669 | * mailbox/mbx_pop.c (pop_readline) : If the server goes away suddenly | ||
670 | return an error. | ||
671 | * mailbox/mbx_pop.c (pop_open) : The ticket comes from the folder. | ||
672 | |||
673 | 2001-03-17 Vesselin Atanasov | ||
674 | |||
675 | * configure.in: AC_REQUIRE is not .. required. Just call | ||
676 | jm_FUNC_MALLOC and jm_FUNC_REALLOC. | ||
677 | |||
678 | 2001-03-17 Alain Magloire | ||
679 | |||
680 | Clean the property object, mailbox and mailer have property object | ||
681 | that you can examine. Still a draft: the value of objects are ints. | ||
682 | This feature was put in to help the imap4d server, in this protocol | ||
683 | you can get a substring of the message starting from a certain offset. | ||
684 | To make the coding of imap4d simpler the complexity was move to the | ||
335 | library. It is possible now by setting a property of the mailbox | 685 | library. It is possible now by setting a property of the mailbox |
336 | to make it output rfc822 stream i.e. "\r\n" terminated stream, the | 686 | to make it output rfc822 stream i.e. "\r\n" terminated stream, the |
337 | offset and the size are also in term of rfc822. | 687 | offset and the size are also in term of rfc822. | ... | ... |
... | @@ -16,6 +16,7 @@ | ... | @@ -16,6 +16,7 @@ |
16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | 16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
17 | 17 | ||
18 | #include "imap4d.h" | 18 | #include "imap4d.h" |
19 | #include <unistd.h> | ||
19 | 20 | ||
20 | /* | 21 | /* |
21 | * must create a new mailbox | 22 | * must create a new mailbox |
... | @@ -24,7 +25,76 @@ | ... | @@ -24,7 +25,76 @@ |
24 | int | 25 | int |
25 | imap4d_create (struct imap4d_command *command, char *arg) | 26 | imap4d_create (struct imap4d_command *command, char *arg) |
26 | { | 27 | { |
28 | char *name; | ||
29 | char *sp = NULL; | ||
30 | const char *delim = "/"; | ||
31 | int rc = RESP_OK; | ||
32 | const char *msg = "Completed"; | ||
33 | |||
27 | if (! (command->states & state)) | 34 | if (! (command->states & state)) |
28 | return util_finish (command, RESP_BAD, "Wrong state"); | 35 | return util_finish (command, RESP_BAD, "Wrong state"); |
29 | return util_finish (command, RESP_NO, "Command not supported"); | 36 | |
37 | name = util_getword (arg, &sp); | ||
38 | if (!name) | ||
39 | return util_finish (command, RESP_BAD, "Too few arguments"); | ||
40 | |||
41 | util_unquote (&name); | ||
42 | |||
43 | if (*name == '\0') | ||
44 | return util_finish (command, RESP_BAD, "Too few arguments"); | ||
45 | |||
46 | /* Creating, "Inbox" should always fail. */ | ||
47 | if (strcasecmp (name, "INBOX") == 0) | ||
48 | return util_finish (command, RESP_BAD, "Already exist"); | ||
49 | |||
50 | /* Allocates memory. */ | ||
51 | name = util_getfullpath (name, delim); | ||
52 | |||
53 | /* It will fail if the mailbx already exists. */ | ||
54 | if (access (name, F_OK) != 0) | ||
55 | { | ||
56 | char *dir; | ||
57 | char *d = name + strlen (delim); /* Pass the root delimeter. */ | ||
58 | if (chdir (delim) == 0) /* start on the root. */ | ||
59 | for (; (dir = strchr (d, delim[0])); d = dir) | ||
60 | { | ||
61 | *dir++ = '\0'; | ||
62 | if (chdir (d) != 0) | ||
63 | { | ||
64 | if (mkdir (d, 0700) == 0) | ||
65 | { | ||
66 | if (chdir (d) == 0) | ||
67 | { | ||
68 | continue; | ||
69 | } | ||
70 | else | ||
71 | { | ||
72 | rc = RESP_NO; | ||
73 | msg = "Can not create mailbox"; | ||
74 | break; | ||
75 | } | ||
76 | } | ||
77 | } | ||
78 | } | ||
79 | /* If it ended with the delim they wanted to create a new folder. */ | ||
80 | if (rc == RESP_OK && d && *d != '\0') | ||
81 | { | ||
82 | int fd = creat (d, 0600); | ||
83 | if (fd != -1) | ||
84 | close (fd); | ||
85 | else | ||
86 | { | ||
87 | rc = RESP_NO; | ||
88 | msg = "Can not create mailbox"; | ||
89 | } | ||
90 | } | ||
91 | } | ||
92 | else | ||
93 | { | ||
94 | rc = RESP_NO; | ||
95 | msg = "already exists"; | ||
96 | } | ||
97 | chdir (homedir); | ||
98 | free (name); | ||
99 | return util_finish (command, rc, msg); | ||
30 | } | 100 | } | ... | ... |
... | @@ -24,7 +24,36 @@ | ... | @@ -24,7 +24,36 @@ |
24 | int | 24 | int |
25 | imap4d_delete (struct imap4d_command *command, char *arg) | 25 | imap4d_delete (struct imap4d_command *command, char *arg) |
26 | { | 26 | { |
27 | char *sp = NULL; | ||
28 | int rc = RESP_OK; | ||
29 | const char *msg = "Completed"; | ||
30 | const char *delim = "/"; | ||
31 | char *name; | ||
32 | |||
27 | if (! (command->states & state)) | 33 | if (! (command->states & state)) |
28 | return util_finish (command, RESP_BAD, "Wrong state"); | 34 | return util_finish (command, RESP_BAD, "Wrong state"); |
29 | return util_finish (command, RESP_NO, "Command not supported");; | 35 | |
36 | name = util_getword (arg, &sp); | ||
37 | if (!name) | ||
38 | return util_finish (command, RESP_BAD, "Too few arguments"); | ||
39 | |||
40 | util_unquote (&name); | ||
41 | |||
42 | if (*name == '\0') | ||
43 | return util_finish (command, RESP_BAD, "Too few arguments"); | ||
44 | |||
45 | /* Deleting, "Inbox" should always fail. */ | ||
46 | if (strcasecmp (name, "INBOX") == 0) | ||
47 | return util_finish (command, RESP_BAD, "Already exist"); | ||
48 | |||
49 | /* Allocates memory. */ | ||
50 | name = util_getfullpath (name, delim); | ||
51 | |||
52 | if (remove (name) != 0) | ||
53 | { | ||
54 | rc = RESP_NO; | ||
55 | msg = "Can not remove"; | ||
56 | } | ||
57 | free (name); | ||
58 | return util_finish (command, rc, msg); | ||
30 | } | 59 | } | ... | ... |
... | @@ -105,7 +105,6 @@ imap4d_fetch (struct imap4d_command *command, char *arg) | ... | @@ -105,7 +105,6 @@ imap4d_fetch (struct imap4d_command *command, char *arg) |
105 | int status; | 105 | int status; |
106 | const char *errmsg = "Completed"; | 106 | const char *errmsg = "Completed"; |
107 | struct imap4d_command *fcmd; | 107 | struct imap4d_command *fcmd; |
108 | char item[32]; | ||
109 | 108 | ||
110 | if (! (command->states & state)) | 109 | if (! (command->states & state)) |
111 | return util_finish (command, RESP_BAD, "Wrong state"); | 110 | return util_finish (command, RESP_BAD, "Wrong state"); |
... | @@ -114,14 +113,8 @@ imap4d_fetch (struct imap4d_command *command, char *arg) | ... | @@ -114,14 +113,8 @@ imap4d_fetch (struct imap4d_command *command, char *arg) |
114 | if (!msgset) | 113 | if (!msgset) |
115 | return util_finish (command, RESP_BAD, "Too few args"); | 114 | return util_finish (command, RESP_BAD, "Too few args"); |
116 | 115 | ||
117 | /* Get the command name. */ | 116 | if (sp == NULL || *sp == '\0') |
118 | item[0] = '\0'; | 117 | return util_finish (command, RESP_BAD, "Too few args"); |
119 | util_token (item, sizeof (item), &sp); | ||
120 | |||
121 | /* Search in the table. */ | ||
122 | fcmd = util_getcommand (item, fetch_command_table); | ||
123 | if (!fcmd) | ||
124 | return util_finish (command, RESP_BAD, "Command unknown"); | ||
125 | 118 | ||
126 | /* Get the message numbers in set[]. */ | 119 | /* Get the message numbers in set[]. */ |
127 | status = util_msgset (msgset, &set, &n, 0); | 120 | status = util_msgset (msgset, &set, &n, 0); |
... | @@ -130,10 +123,26 @@ imap4d_fetch (struct imap4d_command *command, char *arg) | ... | @@ -130,10 +123,26 @@ imap4d_fetch (struct imap4d_command *command, char *arg) |
130 | 123 | ||
131 | for (i = 0; i < n; i++) | 124 | for (i = 0; i < n; i++) |
132 | { | 125 | { |
126 | char item[32]; | ||
127 | char *items = strdup (sp); | ||
128 | char *p = items; | ||
129 | util_send ("* FETCH %d (", set[i]); | ||
130 | item[0] = '\0'; | ||
131 | /* Get the fetch command names. */ | ||
132 | while (*items && *items != ')') | ||
133 | { | ||
134 | util_token (item, sizeof (item), &items); | ||
135 | /* Search in the table. */ | ||
136 | fcmd = util_getcommand (item, fetch_command_table); | ||
137 | if (fcmd) | ||
138 | { | ||
133 | /* We use the states field to hold the msgno/uid. */ | 139 | /* We use the states field to hold the msgno/uid. */ |
134 | fcmd->states = set[i]; | 140 | fcmd->states = set[i]; |
135 | util_send ("* FETCH %d (", set[i]); | 141 | fcmd->func (fcmd, items); |
136 | fcmd->func (fcmd, sp); | 142 | util_send (" "); |
143 | } | ||
144 | } | ||
145 | free (p); | ||
137 | util_send (")\r\n"); | 146 | util_send (")\r\n"); |
138 | } | 147 | } |
139 | free (set); | 148 | free (set); |
... | @@ -358,19 +367,19 @@ fetch_rfc822 (struct imap4d_command *command, char *arg) | ... | @@ -358,19 +367,19 @@ fetch_rfc822 (struct imap4d_command *command, char *arg) |
358 | { | 367 | { |
359 | if (*arg == '.') | 368 | if (*arg == '.') |
360 | { | 369 | { |
361 | if (strcasecmp (arg, ".SIZE") == 0) | 370 | if (strncasecmp (arg, ".SIZE", 5) == 0) |
362 | { | 371 | { |
363 | struct imap4d_command c_rfc= fetch_command_table[F_RFC822_SIZE]; | 372 | struct imap4d_command c_rfc= fetch_command_table[F_RFC822_SIZE]; |
364 | c_rfc.states = command->states; | 373 | c_rfc.states = command->states; |
365 | fetch_rfc822_size (&c_rfc, arg); | 374 | fetch_rfc822_size (&c_rfc, arg); |
366 | } | 375 | } |
367 | else if (strcasecmp (arg, ".TEXT") == 0) | 376 | else if (strncasecmp (arg, ".TEXT", 5) == 0) |
368 | { | 377 | { |
369 | struct imap4d_command c_rfc = fetch_command_table[F_RFC822_TEXT]; | 378 | struct imap4d_command c_rfc = fetch_command_table[F_RFC822_TEXT]; |
370 | c_rfc.states = command->states; | 379 | c_rfc.states = command->states; |
371 | fetch_rfc822_text (&c_rfc, arg); | 380 | fetch_rfc822_text (&c_rfc, arg); |
372 | } | 381 | } |
373 | else if (strcasecmp (arg, ".HEADER") == 0) | 382 | else if (strncasecmp (arg, ".HEADER", 7) == 0) |
374 | { | 383 | { |
375 | struct imap4d_command c_rfc = fetch_command_table[F_RFC822_HEADER]; | 384 | struct imap4d_command c_rfc = fetch_command_table[F_RFC822_HEADER]; |
376 | c_rfc.states = command->states; | 385 | c_rfc.states = command->states; |
... | @@ -824,33 +833,46 @@ fetch_send_address (char *addr) | ... | @@ -824,33 +833,46 @@ fetch_send_address (char *addr) |
824 | util_send ("("); | 833 | util_send ("("); |
825 | 834 | ||
826 | *buf = '\0'; | 835 | *buf = '\0'; |
827 | address_get_personal (address, 1, buf, sizeof (buf), NULL); | 836 | address_get_personal (address, i, buf, sizeof (buf), NULL); |
828 | if (*buf == '\0') | 837 | if (*buf == '\0') |
829 | util_send ("NIL "); | 838 | util_send ("NIL"); |
830 | else | 839 | else |
831 | util_send ("\"%s\" ", buf); | 840 | util_send ("\"%s\"", buf); |
841 | |||
842 | util_send (" "); | ||
832 | 843 | ||
833 | *buf = '\0'; | 844 | *buf = '\0'; |
834 | address_get_route (address, 1, buf, sizeof (buf), NULL); | 845 | address_get_route (address, i, buf, sizeof (buf), NULL); |
835 | if (*buf == '\0') | 846 | if (*buf == '\0') |
836 | util_send ("NIL "); | 847 | util_send ("NIL"); |
837 | else | 848 | else |
838 | util_send ("\"%s\" ", buf); | 849 | util_send ("\"%s\"", buf); |
839 | util_send ("NIL ", buf); | 850 | |
851 | util_send (" "); | ||
840 | 852 | ||
841 | *buf = '\0'; | 853 | *buf = '\0'; |
842 | address_get_local_part (address, 1, buf, sizeof (buf), NULL); | 854 | { |
855 | int is_group = 0; | ||
856 | |||
857 | address_is_group(address, i, &is_group); | ||
858 | if(is_group) | ||
859 | address_get_personal (address, i, buf, sizeof (buf), NULL); | ||
860 | else | ||
861 | address_get_local_part (address, i, buf, sizeof (buf), NULL); | ||
862 | } | ||
843 | if (*buf == '\0') | 863 | if (*buf == '\0') |
844 | util_send ("NIL "); | 864 | util_send ("NIL"); |
845 | else | 865 | else |
846 | util_send ("\"%s\" ", buf); | 866 | util_send ("\"%s\"", buf); |
867 | |||
868 | util_send (" "); | ||
847 | 869 | ||
848 | *buf = '\0'; | 870 | *buf = '\0'; |
849 | address_get_domain (address, 1, buf, sizeof (buf), NULL); | 871 | address_get_domain (address, i, buf, sizeof (buf), NULL); |
850 | if (*buf == '\0') | 872 | if (*buf == '\0') |
851 | util_send ("NIL "); | 873 | util_send ("NIL"); |
852 | else | 874 | else |
853 | util_send ("\"%s\" ", buf); | 875 | util_send ("\"%s\"", buf); |
854 | 876 | ||
855 | util_send (")"); | 877 | util_send (")"); |
856 | } | 878 | } | ... | ... |
... | @@ -47,6 +47,8 @@ | ... | @@ -47,6 +47,8 @@ |
47 | #include <stdarg.h> | 47 | #include <stdarg.h> |
48 | #include <sys/time.h> | 48 | #include <sys/time.h> |
49 | #include <sys/stat.h> | 49 | #include <sys/stat.h> |
50 | #include <dirent.h> | ||
51 | #include <fcntl.h> | ||
50 | 52 | ||
51 | #ifdef HAVE_ALLOCA_H | 53 | #ifdef HAVE_ALLOCA_H |
52 | # include <alloca.h> | 54 | # include <alloca.h> |
... | @@ -111,46 +113,49 @@ extern char *homedir; | ... | @@ -111,46 +113,49 @@ extern char *homedir; |
111 | extern int state; | 113 | extern int state; |
112 | 114 | ||
113 | /* Imap4 commands */ | 115 | /* Imap4 commands */ |
114 | int imap4d_capability __P ((struct imap4d_command *, char *)); | 116 | extern int imap4d_capability __P ((struct imap4d_command *, char *)); |
115 | int imap4d_noop __P ((struct imap4d_command *, char *)); | 117 | extern int imap4d_noop __P ((struct imap4d_command *, char *)); |
116 | int imap4d_logout __P ((struct imap4d_command *, char *)); | 118 | extern int imap4d_logout __P ((struct imap4d_command *, char *)); |
117 | int imap4d_authenticate __P ((struct imap4d_command *, char *)); | 119 | extern int imap4d_authenticate __P ((struct imap4d_command *, char *)); |
118 | int imap4d_login __P ((struct imap4d_command *, char *)); | 120 | extern int imap4d_login __P ((struct imap4d_command *, char *)); |
119 | int imap4d_select __P ((struct imap4d_command *, char *)); | 121 | extern int imap4d_select __P ((struct imap4d_command *, char *)); |
120 | int imap4d_select0 __P ((struct imap4d_command *, char *, int)); | 122 | extern int imap4d_select0 __P ((struct imap4d_command *, char *, int)); |
121 | int imap4d_examine __P ((struct imap4d_command *, char *)); | 123 | extern int imap4d_examine __P ((struct imap4d_command *, char *)); |
122 | int imap4d_create __P ((struct imap4d_command *, char *)); | 124 | extern int imap4d_create __P ((struct imap4d_command *, char *)); |
123 | int imap4d_delete __P ((struct imap4d_command *, char *)); | 125 | extern int imap4d_delete __P ((struct imap4d_command *, char *)); |
124 | int imap4d_rename __P ((struct imap4d_command *, char *)); | 126 | extern int imap4d_rename __P ((struct imap4d_command *, char *)); |
125 | int imap4d_subscribe __P ((struct imap4d_command *, char *)); | 127 | extern int imap4d_subscribe __P ((struct imap4d_command *, char *)); |
126 | int imap4d_unsubscribe __P ((struct imap4d_command *, char *)); | 128 | extern int imap4d_unsubscribe __P ((struct imap4d_command *, char *)); |
127 | int imap4d_list __P ((struct imap4d_command *, char *)); | 129 | extern int imap4d_list __P ((struct imap4d_command *, char *)); |
128 | int imap4d_lsub __P ((struct imap4d_command *, char *)); | 130 | extern int imap4d_lsub __P ((struct imap4d_command *, char *)); |
129 | int imap4d_status __P ((struct imap4d_command *, char *)); | 131 | extern int imap4d_status __P ((struct imap4d_command *, char *)); |
130 | int imap4d_append __P ((struct imap4d_command *, char *)); | 132 | extern int imap4d_append __P ((struct imap4d_command *, char *)); |
131 | int imap4d_check __P ((struct imap4d_command *, char *)); | 133 | extern int imap4d_check __P ((struct imap4d_command *, char *)); |
132 | int imap4d_close __P ((struct imap4d_command *, char *)); | 134 | extern int imap4d_close __P ((struct imap4d_command *, char *)); |
133 | int imap4d_expunge __P ((struct imap4d_command *, char *)); | 135 | extern int imap4d_expunge __P ((struct imap4d_command *, char *)); |
134 | int imap4d_search __P ((struct imap4d_command *, char *)); | 136 | extern int imap4d_search __P ((struct imap4d_command *, char *)); |
135 | int imap4d_fetch __P ((struct imap4d_command *, char *)); | 137 | extern int imap4d_fetch __P ((struct imap4d_command *, char *)); |
136 | int imap4d_store __P ((struct imap4d_command *, char *)); | 138 | extern int imap4d_store __P ((struct imap4d_command *, char *)); |
137 | int imap4d_copy __P ((struct imap4d_command *, char *)); | 139 | extern int imap4d_copy __P ((struct imap4d_command *, char *)); |
138 | int imap4d_uid __P ((struct imap4d_command *, char *)); | 140 | extern int imap4d_uid __P ((struct imap4d_command *, char *)); |
139 | 141 | ||
140 | /* Helper functions. */ | 142 | /* Helper functions. */ |
141 | int util_out __P ((int rc, const char *f, ...)); | 143 | extern int util_out __P ((int, const char *, ...)); |
142 | int util_send __P ((const char *f, ...)); | 144 | extern int util_send __P ((const char *, ...)); |
143 | int util_start __P ((char *tag)); | 145 | extern int util_start __P ((char *)); |
144 | int util_finish __P ((struct imap4d_command *, int sc, const char *f, ...)); | 146 | extern int util_finish __P ((struct imap4d_command *, int, const char *, ...)); |
145 | int util_getstate __P ((void)); | 147 | extern int util_getstate __P ((void)); |
146 | int util_do_command __P ((char *prompt)); | 148 | extern int util_do_command __P ((char *)); |
147 | char *imap4d_readline __P ((int fd)); | 149 | extern char *imap4d_readline __P ((int)); |
148 | void util_quit __P ((int)); | 150 | extern void util_quit __P ((int)); |
149 | char *util_getword __P ((char *s, char **save_ptr)); | 151 | extern char *util_getword __P ((char *, char **)); |
150 | int util_token __P ((char *s, size_t, char **save_ptr)); | 152 | extern int util_token __P ((char *, size_t, char **)); |
151 | int util_msgset __P ((char *s, int **set, int *n, int isuid)); | 153 | extern void util_unquote __P ((char **)); |
152 | int util_upper __P ((char *)); | 154 | extern char *util_tilde_expansion __P ((const char *, const char *)); |
153 | struct imap4d_command *util_getcommand __P ((char *cmd, | 155 | extern char *util_getfullpath __P ((char *, const char *)); |
156 | extern int util_msgset __P ((char *, int **, int *, int)); | ||
157 | extern int util_upper __P ((char *)); | ||
158 | extern struct imap4d_command *util_getcommand __P ((char *, | ||
154 | struct imap4d_command [])); | 159 | struct imap4d_command [])); |
155 | 160 | ||
156 | #ifdef __cplusplus | 161 | #ifdef __cplusplus | ... | ... |
... | @@ -16,168 +16,260 @@ | ... | @@ -16,168 +16,260 @@ |
16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | 16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
17 | 17 | ||
18 | #include "imap4d.h" | 18 | #include "imap4d.h" |
19 | #include <sys/types.h> | ||
20 | #include <sys/stat.h> | ||
21 | #include <dirent.h> | 19 | #include <dirent.h> |
20 | #include <pwd.h> | ||
22 | 21 | ||
22 | #define NOMATCH (0) | ||
23 | #define MATCH (1 << 0) | 23 | #define MATCH (1 << 0) |
24 | #define RECURSE_MATCH (1 << 1) | 24 | #define RECURSE_MATCH (1 << 1) |
25 | #define NOMATCH (1 << 2) | 25 | #define NOSELECT (1 << 2) |
26 | #define NOSELECT (1 << 3) | 26 | #define NOINFERIORS (1 << 3) |
27 | #define NOINFERIORS (1 << 4) | 27 | #define NOSELECT_RECURSE (1 << 4) |
28 | #define NOSELECT_RECURSE (1 << 5) | ||
29 | 28 | ||
30 | /* | 29 | /* |
31 | * | 30 | 1- IMAP4 insists: the reference argument that is include in the |
32 | */ | 31 | interpreted form SHOULD prefix the interpreted form. It SHOULD |
32 | also be in the same form as the reference name argument. This | ||
33 | rule permits the client to determine if the returned mailbox name | ||
34 | is in the context of the reference argument, or if something about | ||
35 | the mailbox argument overrode the reference argument. | ||
36 | ex: | ||
37 | Reference Mailbox --> Interpretation | ||
38 | ~smith/Mail foo.* --> ~smith/Mail/foo.* | ||
39 | archive % --> archive/% | ||
40 | #news comp.mail.* --> #news.comp.mail.* | ||
41 | ~smith/Mail /usr/doc/foo --> /usr/doc/foo | ||
42 | archive ~fred/Mail --> ~fred/Mail/ * | ||
33 | 43 | ||
34 | static void unquote (char **); | 44 | 2- The character "*" is a wildcard, and matches zero or more characters |
35 | static int match (const char *, const char *); | 45 | at this position. The charcater "%" is similar to "*", |
36 | static int imap_match (const char *, const char *); | 46 | but it does not match ahierarchy delimiter. */ |
37 | static void list_file (const char *, const char *); | 47 | |
38 | static char *expand (const char *); | 48 | static int match __P ((const char *, const char *, const char *)); |
39 | static void print_file (const char *, const char *); | 49 | static int imap_match __P ((const char *, const char *, const char *)); |
40 | static void print_dir (const char *, const char *); | 50 | static void list_file __P ((const char *, const char *, char *, const char *)); |
51 | static void print_file __P ((const char *, const char *, const char *)); | ||
52 | static void print_dir __P ((const char *, const char *, const char *)); | ||
41 | 53 | ||
42 | int | 54 | int |
43 | imap4d_list (struct imap4d_command *command, char *arg) | 55 | imap4d_list (struct imap4d_command *command, char *arg) |
44 | { | 56 | { |
45 | char *sp = NULL; | 57 | char *sp = NULL; |
46 | char *reference; | 58 | char *ref; |
47 | char *wildcard; | 59 | char *wcard; |
60 | const char *delim = "/"; | ||
48 | 61 | ||
49 | if (! (command->states & state)) | 62 | if (! (command->states & state)) |
50 | return util_finish (command, RESP_BAD, "Wrong state"); | 63 | return util_finish (command, RESP_BAD, "Wrong state"); |
51 | 64 | ||
52 | reference = util_getword (arg, &sp); | 65 | ref = util_getword (arg, &sp); |
53 | wildcard = util_getword (NULL, &sp); | 66 | wcard = util_getword (NULL, &sp); |
54 | if (!reference || !wildcard) | 67 | if (!ref || !wcard) |
55 | return util_finish (command, RESP_BAD, "Too few arguments"); | 68 | return util_finish (command, RESP_BAD, "Too few arguments"); |
56 | 69 | ||
57 | unquote (&reference); | 70 | /* Remove the double quotes. */ |
58 | unquote (&wildcard); | 71 | util_unquote (&ref); |
59 | if (*wildcard == '\0') | 72 | util_unquote (&wcard); |
73 | |||
74 | /* If wildcard is empty, it is a special case: we have to | ||
75 | return the hierarchy. */ | ||
76 | if (*wcard == '\0') | ||
60 | { | 77 | { |
61 | /* FIXME: How do we know the hierarchy delimeter. */ | 78 | util_out (RESP_NONE, "LIST (\\NoSelect) \"%s\" \"%s\"", delim, |
62 | util_out (RESP_NONE, "LIST (\\NoSelect) \"/\" \"%s\"", | 79 | (*ref) ? delim : ""); |
63 | (*reference == '\0' || *reference != '/') ? "" : "/"); | 80 | } |
81 | /* There is only one mailbox in the "INBOX" hierarchy ... INBOX. */ | ||
82 | else if (strcasecmp (ref, "INBOX") == 0) | ||
83 | { | ||
84 | util_out (RESP_NONE, "LIST (\\NoInferiors) NIL INBOX"); | ||
64 | } | 85 | } |
65 | else | 86 | else |
66 | { | 87 | { |
67 | char *p; | 88 | char *cwd; |
68 | 89 | char *dir; | |
69 | if (*reference == '\0') | 90 | switch (*wcard) |
70 | reference = homedir; | 91 | { |
92 | /* Absolute Path in wcard, dump the old ref. */ | ||
93 | case '/': | ||
94 | { | ||
95 | ref = calloc (2, 1); | ||
96 | ref[0] = *wcard; | ||
97 | wcard++; | ||
98 | } | ||
99 | break; | ||
71 | 100 | ||
72 | p = expand (reference); | 101 | /* Absolute Path, but take care of things like ~guest/Mail, |
73 | if (chdir (p) == 0) | 102 | ref becomes ref = ~guest. */ |
103 | case '~': | ||
74 | { | 104 | { |
75 | list_file (reference, wildcard); | 105 | char *s = strchr (wcard, '/'); |
76 | chdir (homedir); | 106 | if (s) |
107 | { | ||
108 | ref = calloc (s - wcard + 1, 1); | ||
109 | memcpy (ref, wcard, s - wcard); | ||
110 | ref [s - wcard] = '\0'; | ||
111 | wcard = s + 1; | ||
77 | } | 112 | } |
78 | free (p); | 113 | else |
114 | { | ||
115 | ref = strdup (wcard); | ||
116 | wcard += strlen (wcard); | ||
79 | } | 117 | } |
80 | return util_finish (command, RESP_OK, "Completed"); | 118 | } |
81 | } | 119 | break; |
82 | |||
83 | /* expand the '~' */ | ||
84 | static char * | ||
85 | expand (const char *ref) | ||
86 | { | ||
87 | /* FIXME: note done. */ | ||
88 | return strdup (ref); | ||
89 | } | ||
90 | 120 | ||
91 | /* Remove the surrounding double quotes. */ | 121 | default: |
92 | static void | 122 | ref = strdup (ref); |
93 | unquote (char **ptr) | ||
94 | { | ||
95 | char *s = *ptr; | ||
96 | if (*s == '"') | ||
97 | { | ||
98 | char *p = ++s; | ||
99 | while (*p && *p != '"') | ||
100 | p++; | ||
101 | if (*p == '"') | ||
102 | *p = '\0'; | ||
103 | } | 123 | } |
104 | *ptr = s; | ||
105 | } | ||
106 | 124 | ||
107 | static void | 125 | /* Move any directory not containing a wildcard into the reference |
108 | print_file (const char *ref, const char *file) | 126 | So (ref = ~guest, wcard = Mail/folder1/%.vf) --> |
109 | { | 127 | (ref = ~guest/Mail/folder1, wcard = %.vf). */ |
110 | if (strpbrk (file, "\"{}")) | 128 | for (; (dir = strpbrk (wcard, "/%*")); wcard = dir) |
129 | { | ||
130 | if (*dir == '/') | ||
111 | { | 131 | { |
112 | util_out (RESP_NONE, "LIST (\\NoInferior \\UnMarked) \"/\" {%d}", | 132 | *dir = '\0'; |
113 | strlen (ref) + strlen ((*ref) ? "/" : "") + strlen (file)); | 133 | ref = realloc (ref, strlen (ref) + 1 + (dir - wcard) + 1); |
114 | util_send ("%s%s%s\r\n", ref, (*ref) ? "/" : "", file); | 134 | if (*ref && ref[strlen (ref) - 1] != '/') |
135 | strcat (ref, "/"); | ||
136 | strcat (ref, wcard); | ||
137 | dir++; | ||
115 | } | 138 | } |
116 | else | 139 | else |
117 | util_out (RESP_NONE, "LIST (\\NoInferior \\UnMarked) \"/\" %s%s%s", | 140 | break; |
118 | ref, (*ref) ? "/" : "", file); | 141 | } |
119 | } | ||
120 | 142 | ||
121 | static void | 143 | /* Allocates. */ |
122 | print_dir (const char *ref, const char *file) | 144 | cwd = util_getfullpath (ref, delim); |
123 | { | 145 | |
124 | if (strpbrk (file, "\"{}")) | 146 | /* If wcard match inbox return it too, part of the list. */ |
147 | if (!*ref && (match ("INBOX", wcard, delim) | ||
148 | || match ("inbox", wcard, delim))) | ||
149 | util_out (RESP_NONE, "LIST (\\NoInferiors) NIL INBOX"); | ||
150 | |||
151 | if (chdir (cwd) == 0) | ||
125 | { | 152 | { |
126 | util_out (RESP_NONE, "LIST (\\NoSelect) \"/\" {%d}", | 153 | list_file (cwd, ref, dir, delim); |
127 | strlen (ref) + strlen ((*ref) ? "/" : "") + strlen (file)); | 154 | chdir (homedir); |
128 | util_send ("%s%s%s\r\n", ref, (*ref) ? "/" : "", file); | ||
129 | } | 155 | } |
130 | else | 156 | free (cwd); |
131 | util_out (RESP_NONE, "LIST (\\NoSelect) \"/\" %s%s%s", | 157 | free (ref); |
132 | ref, (*ref) ? "/" : "", file); | 158 | } |
159 | return util_finish (command, RESP_OK, "Completed"); | ||
133 | } | 160 | } |
134 | 161 | ||
135 | /* Recusively calling the files. */ | 162 | /* Recusively calling the files. */ |
136 | static void | 163 | static void |
137 | list_file (const char *ref, const char *pattern) | 164 | list_file (const char *cwd, const char *ref, char *pattern, const char *delim) |
138 | { | 165 | { |
139 | DIR *dirp; | 166 | DIR *dirp; |
140 | struct dirent *dp; | 167 | struct dirent *dp; |
168 | char *next; | ||
169 | |||
170 | /* Shortcut no wildcards. */ | ||
171 | if (!strpbrk (pattern, "%*")) | ||
172 | { | ||
173 | /* Equivalent to stat(). */ | ||
174 | int status = match (pattern, pattern, delim); | ||
175 | if (status & NOSELECT) | ||
176 | print_dir (ref, pattern, delim); | ||
177 | else if (status & NOINFERIORS) | ||
178 | print_file (ref, pattern, delim); | ||
179 | return ; | ||
180 | } | ||
141 | 181 | ||
142 | dirp = opendir ("."); | 182 | dirp = opendir ("."); |
143 | if (dirp == NULL) | 183 | if (dirp == NULL) |
144 | return; | 184 | return; |
145 | 185 | ||
186 | next = strchr (pattern, delim[0]); | ||
187 | if (next) | ||
188 | *next++ = '\0'; | ||
146 | while ((dp = readdir (dirp)) != NULL) | 189 | while ((dp = readdir (dirp)) != NULL) |
147 | { | 190 | { |
148 | int status = match (dp->d_name, pattern); | 191 | /* Skip "", ".", and "..". "" is returned by at least one buggy |
149 | if (status & (MATCH | RECURSE_MATCH)) | 192 | implementation: Solaris 2.4 readdir on NFS filesystems. */ |
193 | char const *entry = dp->d_name; | ||
194 | if (entry[entry[0] != '.' ? 0 : entry[1] != '.' ? 1 : 2] != '\0') | ||
195 | { | ||
196 | int status = match (entry, pattern, delim); | ||
197 | if (status) | ||
150 | { | 198 | { |
151 | if (status & NOSELECT) | 199 | if (status & NOSELECT) |
152 | { | 200 | { |
153 | print_dir (ref, dp->d_name); | 201 | if (next || status & RECURSE_MATCH) |
154 | if (status & RECURSE_MATCH) | ||
155 | { | 202 | { |
156 | if (chdir (dp->d_name) == 0) | 203 | if (!next) |
204 | print_dir (ref, entry, delim); | ||
205 | if (chdir (entry) == 0) | ||
157 | { | 206 | { |
158 | char *buffer = NULL; | 207 | char *rf; |
159 | asprintf (&buffer, "%s%s%s", ref, | 208 | char *cd; |
160 | (*ref) ? "/" : "", dp->d_name); | 209 | rf = calloc (strlen (ref) + strlen (delim) + |
161 | list_file (buffer, pattern); | 210 | strlen (entry) + 1, 1); |
162 | free (buffer); | 211 | sprintf (rf, "%s%s%s", ref, delim, entry); |
163 | chdir (".."); | 212 | cd = calloc (strlen (cwd) + strlen (delim) + |
213 | strlen (entry) + 1, 1); | ||
214 | sprintf (cd, "%s%s%s", cwd, delim, entry); | ||
215 | list_file (cd, rf, (next) ? next : pattern, delim); | ||
216 | free (rf); | ||
217 | free (cd); | ||
218 | chdir (cwd); | ||
164 | } | 219 | } |
165 | } | 220 | } |
221 | else | ||
222 | print_dir (ref, entry, delim); | ||
166 | } | 223 | } |
167 | else if (status & NOINFERIORS) | 224 | else if (status & NOINFERIORS) |
168 | { | 225 | { |
169 | print_file (ref, dp->d_name); | 226 | print_file (ref, entry, delim); |
170 | } | 227 | } |
171 | } | 228 | } |
172 | } | 229 | } |
230 | } | ||
231 | closedir (dirp); | ||
232 | } | ||
233 | |||
234 | /* Make sure that the file name does not contain any undesirable | ||
235 | chars like "{}. If yes send it as a literal string. */ | ||
236 | static void | ||
237 | print_file (const char *ref, const char *file, const char *delim) | ||
238 | { | ||
239 | if (strpbrk (file, "\"{}")) | ||
240 | { | ||
241 | util_out (RESP_NONE, "LIST (\\NoInferiors) \"%s\" {%d}", delim, | ||
242 | strlen (ref) + strlen ((*ref) ? delim : "") + strlen (file)); | ||
243 | util_send ("%s%s%s\r\n", ref, (*ref) ? delim : "", file); | ||
244 | } | ||
245 | else | ||
246 | util_out (RESP_NONE, "LIST (\\NoInferiors) \"%s\" %s%s%s", delim, | ||
247 | ref, (*ref) ? delim : "", file); | ||
248 | } | ||
249 | |||
250 | /* Make sure that the file name does not contain any undesirable | ||
251 | chars like "{}. If yes send it as a literal string. */ | ||
252 | static void | ||
253 | print_dir (const char *ref, const char *file, const char *delim) | ||
254 | { | ||
255 | if (strpbrk (file, "\"{}")) | ||
256 | { | ||
257 | util_out (RESP_NONE, "LIST (\\NoSelect) \"%s\" {%d}", delim, | ||
258 | strlen (ref) + strlen ((*ref) ? delim : "") + strlen (file)); | ||
259 | util_send ("%s%s%s\r\n", ref, (*ref) ? delim : "", file); | ||
260 | } | ||
261 | else | ||
262 | util_out (RESP_NONE, "LIST (\\NoSelect) \"%s\" %s%s%s", delim, | ||
263 | ref, (*ref) ? delim : "", file); | ||
173 | } | 264 | } |
174 | 265 | ||
266 | /* Calls the imap_matcher if a match found out the attribute. */ | ||
175 | static int | 267 | static int |
176 | match (const char *entry, const char *pattern) | 268 | match (const char *entry, const char *pattern, const char *delim) |
177 | { | 269 | { |
178 | struct stat stats; | 270 | struct stat stats; |
179 | int status = imap_match (entry, pattern); | 271 | int status = imap_match (entry, pattern, delim); |
180 | if (status & MATCH || status || RECURSE_MATCH) | 272 | if (status) |
181 | { | 273 | { |
182 | if (stat (entry, &stats) == 0) | 274 | if (stat (entry, &stats) == 0) |
183 | status |= (S_ISREG (stats.st_mode)) ? NOINFERIORS : NOSELECT; | 275 | status |= (S_ISREG (stats.st_mode)) ? NOINFERIORS : NOSELECT; |
... | @@ -188,20 +280,26 @@ match (const char *entry, const char *pattern) | ... | @@ -188,20 +280,26 @@ match (const char *entry, const char *pattern) |
188 | /* Match STRING against the filename pattern PATTERN, returning zero if | 280 | /* Match STRING against the filename pattern PATTERN, returning zero if |
189 | it matches, nonzero if not. */ | 281 | it matches, nonzero if not. */ |
190 | static int | 282 | static int |
191 | imap_match (const char *string, const char *pattern) | 283 | imap_match (const char *string, const char *pattern, const char *delim) |
192 | { | 284 | { |
193 | const char *p = pattern, *n = string; | 285 | const char *p = pattern, *n = string; |
194 | char c; | 286 | char c; |
195 | 287 | ||
196 | for (;(c = *p++) != '\0'; n++) | 288 | for (;(c = *p++) != '\0' && *n; n++) |
197 | { | 289 | { |
198 | switch (c) | 290 | switch (c) |
199 | { | 291 | { |
200 | case '%': | 292 | case '%': |
201 | if (*p == '\0') | 293 | if (*p == '\0') |
202 | return (*n == '/') ? NOMATCH : MATCH; | 294 | { |
295 | /* Matches everything except '/' */ | ||
296 | for (; *n && *n != delim[0]; n++) | ||
297 | ; | ||
298 | return (*n == '/') ? RECURSE_MATCH : MATCH; | ||
299 | } | ||
300 | else | ||
203 | for (; *n != '\0'; ++n) | 301 | for (; *n != '\0'; ++n) |
204 | if (match (n, p) == MATCH) | 302 | if (imap_match (n, p, delim) == MATCH) |
205 | return MATCH; | 303 | return MATCH; |
206 | break; | 304 | break; |
207 | 305 | ||
... | @@ -210,7 +308,7 @@ imap_match (const char *string, const char *pattern) | ... | @@ -210,7 +308,7 @@ imap_match (const char *string, const char *pattern) |
210 | return RECURSE_MATCH; | 308 | return RECURSE_MATCH; |
211 | for (; *n != '\0'; ++n) | 309 | for (; *n != '\0'; ++n) |
212 | { | 310 | { |
213 | int status = match (n, p); | 311 | int status = imap_match (n, p, delim); |
214 | if (status == MATCH || status == RECURSE_MATCH) | 312 | if (status == MATCH || status == RECURSE_MATCH) |
215 | return status; | 313 | return status; |
216 | } | 314 | } |
... | @@ -222,10 +320,9 @@ imap_match (const char *string, const char *pattern) | ... | @@ -222,10 +320,9 @@ imap_match (const char *string, const char *pattern) |
222 | } | 320 | } |
223 | } | 321 | } |
224 | 322 | ||
225 | if (*n == '\0') | 323 | if (!c && !*n) |
226 | return MATCH; | 324 | return MATCH; |
227 | 325 | ||
228 | return NOMATCH; | 326 | return NOMATCH; |
229 | 327 | ||
230 | } | 328 | } |
231 | ... | ... |
... | @@ -24,7 +24,109 @@ | ... | @@ -24,7 +24,109 @@ |
24 | int | 24 | int |
25 | imap4d_rename (struct imap4d_command *command, char *arg) | 25 | imap4d_rename (struct imap4d_command *command, char *arg) |
26 | { | 26 | { |
27 | char *oldname; | ||
28 | char *newname; | ||
29 | char *sp = NULL; | ||
30 | int rc = RESP_OK; | ||
31 | const char *msg = "Completed"; | ||
32 | struct stat newst; | ||
33 | const char *delim = "/"; | ||
34 | |||
27 | if (! (command->states & state)) | 35 | if (! (command->states & state)) |
28 | return util_finish (command, RESP_BAD, "Wrong state"); | 36 | return util_finish (command, RESP_BAD, "Wrong state"); |
29 | return util_finish (command, RESP_NO, "Not Supported"); | 37 | |
38 | oldname = util_getword (arg, &sp); | ||
39 | newname = util_getword (NULL, &sp); | ||
40 | if (!newname || !oldname) | ||
41 | return util_finish (command, RESP_BAD, "Too few arguments"); | ||
42 | |||
43 | util_unquote (&newname); | ||
44 | util_unquote (&oldname); | ||
45 | |||
46 | if (*newname == '\0' || *oldname == '\0') | ||
47 | return util_finish (command, RESP_BAD, "Too few arguments"); | ||
48 | |||
49 | if (strcasecmp (newname, "INBOX") == 0) | ||
50 | return util_finish (command, RESP_NO, "Name Inbox is reservered"); | ||
51 | |||
52 | /* Allocates memory. */ | ||
53 | newname = util_getfullpath (newname, delim); | ||
54 | |||
55 | /* It is an error to attempt to rename from a mailbox name that already | ||
56 | exist. */ | ||
57 | if (stat (newname, &newst) == 0) | ||
58 | { | ||
59 | if (!S_ISDIR(newst.st_mode)) | ||
60 | { | ||
61 | free (newname); | ||
62 | return util_finish (command, RESP_NO, "Already exist, delete first"); | ||
63 | } | ||
64 | } | ||
65 | |||
66 | /* Renaming INBOX is permitted, and has special behavior. It moves | ||
67 | all messages in INBOX to a new mailbox with the given name, | ||
68 | leaving INBOX empty. */ | ||
69 | if (strcasecmp (oldname, "INBOX") == 0) | ||
70 | { | ||
71 | mailbox_t newmbox = NULL; | ||
72 | char *name; | ||
73 | struct passwd *pw; | ||
74 | if (S_ISDIR(newst.st_mode)) | ||
75 | { | ||
76 | free (newname); | ||
77 | return util_finish (command, RESP_NO, "Can not be a directory"); | ||
78 | } | ||
79 | name = calloc (strlen ("mbox:") + strlen (newname) + 1, 1); | ||
80 | sprintf (name, "mbox:%s", newname); | ||
81 | if (mailbox_create (&newmbox, newname) != 0 | ||
82 | || mailbox_open (newmbox, MU_STREAM_CREAT | MU_STREAM_RDWR) != 0) | ||
83 | { | ||
84 | free (name); | ||
85 | free (newname); | ||
86 | return util_finish (command, RESP_NO, "Can not create new mailbox"); | ||
87 | } | ||
88 | free (name); | ||
89 | free (newname); | ||
90 | pw = getpwuid (getuid ()); | ||
91 | if (pw) | ||
92 | { | ||
93 | mailbox_t inbox = NULL; | ||
94 | if (mailbox_create_default (&inbox, pw->pw_name) == 0 && | ||
95 | mailbox_open (inbox, MU_STREAM_RDWR) == 0) | ||
96 | { | ||
97 | size_t no; | ||
98 | size_t total = 0; | ||
99 | mailbox_messages_count (inbox, &total); | ||
100 | for (no = 1; no <= total; no++) | ||
101 | { | ||
102 | message_t message; | ||
103 | if (mailbox_get_message (inbox, no, &message) == 0) | ||
104 | { | ||
105 | attribute_t attr = NULL; | ||
106 | mailbox_append_message (newmbox, message); | ||
107 | message_get_attribute (message, &attr); | ||
108 | attribute_set_deleted (attr); | ||
109 | } | ||
110 | } | ||
111 | mailbox_expunge (inbox); | ||
112 | mailbox_close (inbox); | ||
113 | mailbox_destroy (&inbox); | ||
114 | } | ||
115 | } | ||
116 | mailbox_close (newmbox); | ||
117 | mailbox_destroy (&newmbox); | ||
118 | return util_finish (command, RESP_OK, "Already exist"); | ||
119 | } | ||
120 | |||
121 | oldname = util_getfullpath (oldname, delim); | ||
122 | |||
123 | /* It must exist. */ | ||
124 | if (rename (oldname, newname) != 0) | ||
125 | { | ||
126 | rc = RESP_NO; | ||
127 | msg = "Failed"; | ||
128 | } | ||
129 | free (oldname); | ||
130 | free (newname); | ||
131 | return util_finish (command, rc, msg); | ||
30 | } | 132 | } | ... | ... |
... | @@ -58,6 +58,9 @@ util_token (char *buf, size_t len, char **ptr) | ... | @@ -58,6 +58,9 @@ util_token (char *buf, size_t len, char **ptr) |
58 | /* Skip leading space. */ | 58 | /* Skip leading space. */ |
59 | while (**ptr && **ptr == ' ') | 59 | while (**ptr && **ptr == ' ') |
60 | (*ptr)++; | 60 | (*ptr)++; |
61 | |||
62 | /* Break the string by token, i.e when we reconize IMAP special | ||
63 | atoms we stop and send it. */ | ||
61 | for (i = 1; **ptr && i < len; (*ptr)++, buf++, i++) | 64 | for (i = 1; **ptr && i < len; (*ptr)++, buf++, i++) |
62 | { | 65 | { |
63 | if (**ptr == ' ' || **ptr == '.' | 66 | if (**ptr == ' ' || **ptr == '.' |
... | @@ -76,7 +79,82 @@ util_token (char *buf, size_t len, char **ptr) | ... | @@ -76,7 +79,82 @@ util_token (char *buf, size_t len, char **ptr) |
76 | /* Skip trailing space. */ | 79 | /* Skip trailing space. */ |
77 | while (**ptr && **ptr == ' ') | 80 | while (**ptr && **ptr == ' ') |
78 | (*ptr)++; | 81 | (*ptr)++; |
79 | return *ptr - start;; | 82 | return *ptr - start; |
83 | } | ||
84 | |||
85 | /* Remove the surrounding double quotes. */ | ||
86 | void | ||
87 | util_unquote (char **ptr) | ||
88 | { | ||
89 | char *s = *ptr; | ||
90 | if (*s == '"') | ||
91 | { | ||
92 | char *p = ++s; | ||
93 | while (*p && *p != '"') | ||
94 | p++; | ||
95 | if (*p == '"') | ||
96 | *p = '\0'; | ||
97 | } | ||
98 | *ptr = s; | ||
99 | } | ||
100 | |||
101 | /* NOTE: Allocates Memory. */ | ||
102 | /* Expand: ~ --> /home/user and to ~guest --> /home/guest. */ | ||
103 | char * | ||
104 | util_tilde_expansion (const char *ref, const char *delim) | ||
105 | { | ||
106 | char *p = strdup (ref); | ||
107 | if (*p == '~') | ||
108 | { | ||
109 | p++; | ||
110 | if (*p == delim[0] || *p == '\0') | ||
111 | { | ||
112 | char *s = calloc (strlen (homedir) + strlen (p) + 1, 1); | ||
113 | strcpy (s, homedir); | ||
114 | strcat (s, p); | ||
115 | free (--p); | ||
116 | p = s; | ||
117 | } | ||
118 | else | ||
119 | { | ||
120 | struct passwd *pw; | ||
121 | char *s = p; | ||
122 | char *name; | ||
123 | while (*s && *s != delim[0]) | ||
124 | s++; | ||
125 | name = calloc (s - p + 1, 1); | ||
126 | memcpy (name, p, s - p); | ||
127 | name [s - p] = '\0'; | ||
128 | pw = getpwnam (name); | ||
129 | free (name); | ||
130 | if (pw) | ||
131 | { | ||
132 | char *buf = calloc (strlen (pw->pw_dir) + strlen (s) + 1, 1); | ||
133 | strcpy (buf, pw->pw_dir); | ||
134 | strcat (buf, s); | ||
135 | free (--p); | ||
136 | p = buf; | ||
137 | } | ||
138 | else | ||
139 | p--; | ||
140 | } | ||
141 | } | ||
142 | return p; | ||
143 | } | ||
144 | |||
145 | /* Absolute path. */ | ||
146 | char * | ||
147 | util_getfullpath (char *name, const char *delim) | ||
148 | { | ||
149 | char *p = util_tilde_expansion (name, delim); | ||
150 | if (*p != delim[0]) | ||
151 | { | ||
152 | char *s = calloc (strlen (homedir) + strlen (delim) + strlen (p) + 1, 1); | ||
153 | sprintf (s, "%s%s%s", homedir, delim, p); | ||
154 | free (p); | ||
155 | p = s; | ||
156 | } | ||
157 | return p; | ||
80 | } | 158 | } |
81 | 159 | ||
82 | /* Return in set an allocated array contain (n) numbers, for imap messsage set | 160 | /* Return in set an allocated array contain (n) numbers, for imap messsage set | ... | ... |
... | @@ -346,7 +346,7 @@ int message_unencapsulate(message_t msg, message_t *newmsg, void **data) | ... | @@ -346,7 +346,7 @@ int message_unencapsulate(message_t msg, message_t *newmsg, void **data) |
346 | if ( ( content_type = alloca(size+1) ) == NULL ) | 346 | if ( ( content_type = alloca(size+1) ) == NULL ) |
347 | return ENOMEM; | 347 | return ENOMEM; |
348 | header_get_value(hdr, "Content-Type", content_type, size+1, 0); | 348 | header_get_value(hdr, "Content-Type", content_type, size+1, 0); |
349 | if ( strncasecmp(content_type, "message/rfc822", strlen(content_type)) != 0 ) | 349 | if ( strncasecmp(content_type, "message/rfc822", strlen("message/rfc822")) != 0 ) |
350 | return EINVAL; | 350 | return EINVAL; |
351 | } else | 351 | } else |
352 | return EINVAL; | 352 | return EINVAL; | ... | ... |
... | @@ -1533,6 +1533,7 @@ imap_token (char *buf, size_t len, char **ptr) | ... | @@ -1533,6 +1533,7 @@ imap_token (char *buf, size_t len, char **ptr) |
1533 | /* Skip leading space. */ | 1533 | /* Skip leading space. */ |
1534 | while (**ptr && **ptr == ' ') | 1534 | while (**ptr && **ptr == ' ') |
1535 | (*ptr)++; | 1535 | (*ptr)++; |
1536 | /* Break the string by token, when we recognise Atoms we stop. */ | ||
1536 | for (i = 1; **ptr && i < len; (*ptr)++, buf++, i++) | 1537 | for (i = 1; **ptr && i < len; (*ptr)++, buf++, i++) |
1537 | { | 1538 | { |
1538 | if (**ptr == ' ' || **ptr == '.' | 1539 | if (**ptr == ' ' || **ptr == '.' | ... | ... |
-
Please register or sign in to post a comment