Commit 2b99aa95 2b99aa9530eb3001e8015df35993d245383ffcca by Alain Magloire

* 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.
1 parent 29972003
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 == '.'
......