Commit ed1175f9 ed1175f91d78846077062af5cf8a969dbaff80a6 by Alain Magloire

* mail/mail.c: Possibility to enable debuging output.

	It should probably be a runtime option via set debug=1 or something
	for now it is disable between if (0) {...}.

	More cleanup in the IMAP code.  A memory stream buffer is
	use to save the string literal sended by the IMAP server.
	The allocation is handle by the memory_stream which simplifies
	the code.

	* folder_imap.c (folder_imap.c): Create a memory stream to
	hold the literal or quoted string send by the IMAP server.
	(folder_imap_list folder_imap_lsub): There is no callback
	field the struct folder_list is in struct _f_imap now.
	(imap_literal_string imap_quoted_string imap_string):  Use the
	memory string stream to save the result.
	(imap_body): Still need to be clean, but creates the cache
	header when doing the scan.
	(imap_parse): Do not use alloca().
1 parent a59f00d4
1 2001-10-13 Jeff Bailey <jbailey@outpost.dnsalias.org> 1 2001-10-13 Alain Malgoire
2
3 * mail/mail.c: Possibility to enable debuging output.
4 It should probably be a runtime option via set debug=1 or something
5 for now it is disable between if (0) {...}.
6
7 More cleanup in the IMAP code. A memory stream buffer is
8 use to save the string literal sended by the IMAP server.
9 The allocation is handle by the memory_stream which simplifies
10 the code.
11
12 * folder_imap.c (folder_imap.c): Create a memory stream to
13 hold the literal or quoted string send by the IMAP server.
14 (folder_imap_list folder_imap_lsub): There is no callback
15 field the struct folder_list is in struct _f_imap now.
16 (imap_literal_string imap_quoted_string imap_string): Use the
17 memory string stream to save the result.
18 (imap_body): Still need to be clean, but creates the cache
19 header when doing the scan.
20 (imap_parse): Do not use alloca().
21
22 2001-10-13 Jeff Bailey
2 23
3 * guimb/Makefile.am: Remove GNU Makeism. 24 * guimb/Makefile.am: Remove GNU Makeism.
4 25
5 * libmu_scm/Makefile.am: Remove GNU Makeism. 26 * libmu_scm/Makefile.am: Remove GNU Makeism.
6 27
7 2001-10-12 Jeff Bailey <jbailey@outpost.dnsalias.org> 28 2001-10-12 Jeff Bailey
8 29
9 * libmu_scm/Makefile.am: Fixes for RO srcdir. 30 * libmu_scm/Makefile.am: Fixes for RO srcdir.
10 31
......
...@@ -345,6 +345,14 @@ main (int argc, char **argv) ...@@ -345,6 +345,14 @@ main (int argc, char **argv)
345 exit (EXIT_FAILURE); 345 exit (EXIT_FAILURE);
346 } 346 }
347 347
348 /* Could we enable this at runtime, via the a set environment? */
349 if (0)
350 {
351 mu_debug_t debug = NULL;
352 mailbox_get_debug (mbox, &debug);
353 mu_debug_set_level (debug, MU_DEBUG_TRACE|MU_DEBUG_PROT);
354 }
355
348 if (mailbox_open (mbox, MU_STREAM_RDWR) != 0) 356 if (mailbox_open (mbox, MU_STREAM_RDWR) != 0)
349 { 357 {
350 util_error ("Can not open mailbox"); 358 util_error ("Can not open mailbox");
......
...@@ -264,11 +264,15 @@ folder_imap_open (folder_t folder, int flags) ...@@ -264,11 +264,15 @@ folder_imap_open (folder_t folder, int flags)
264 { 264 {
265 CHECK_ERROR (f_imap, ENOMEM); 265 CHECK_ERROR (f_imap, ENOMEM);
266 } 266 }
267 memory_stream_create (&f_imap->string.stream);
267 } 268 }
268 else 269 else
269 { 270 {
270 /* Clear from any residue. */ 271 /* Clear from any residue. */
271 memset (f_imap->buffer, '\0', f_imap->buflen); 272 memset (f_imap->buffer, '\0', f_imap->buflen);
273 stream_truncate (f_imap->string.stream, 0);
274 f_imap->string.offset = 0;
275 f_imap->string.nleft = 0;
272 } 276 }
273 f_imap->ptr = f_imap->buffer; 277 f_imap->ptr = f_imap->buffer;
274 278
...@@ -598,10 +602,10 @@ folder_imap_list (folder_t folder, const char *ref, const char *name, ...@@ -598,10 +602,10 @@ folder_imap_list (folder_t folder, const char *ref, const char *name,
598 } 602 }
599 603
600 /* Build the folder list. */ 604 /* Build the folder list. */
601 if (f_imap->callback.flist.num > 0) 605 if (f_imap->flist.num > 0)
602 { 606 {
603 struct list_response **plist = NULL; 607 struct list_response **plist = NULL;
604 size_t num = f_imap->callback.flist.num; 608 size_t num = f_imap->flist.num;
605 size_t j = 0; 609 size_t j = 0;
606 plist = calloc (num, sizeof (*plist)); 610 plist = calloc (num, sizeof (*plist));
607 if (plist) 611 if (plist)
...@@ -609,7 +613,7 @@ folder_imap_list (folder_t folder, const char *ref, const char *name, ...@@ -609,7 +613,7 @@ folder_imap_list (folder_t folder, const char *ref, const char *name,
609 size_t i; 613 size_t i;
610 for (i = 0; i < num; i++) 614 for (i = 0; i < num; i++)
611 { 615 {
612 struct list_response *lr = f_imap->callback.flist.element[i]; 616 struct list_response *lr = f_imap->flist.element[i];
613 /* printf ("%s --> %s\n", lr->name, name); */ 617 /* printf ("%s --> %s\n", lr->name, name); */
614 if (fnmatch (name, lr->name, 0) == 0) 618 if (fnmatch (name, lr->name, 0) == 0)
615 { 619 {
...@@ -628,7 +632,7 @@ folder_imap_list (folder_t folder, const char *ref, const char *name, ...@@ -628,7 +632,7 @@ folder_imap_list (folder_t folder, const char *ref, const char *name,
628 pflist->element = plist; 632 pflist->element = plist;
629 pflist->num = j; 633 pflist->num = j;
630 } 634 }
631 folder_list_destroy (&(f_imap->callback.flist)); 635 folder_list_destroy (&(f_imap->flist));
632 f_imap->state = IMAP_NO_STATE; 636 f_imap->state = IMAP_NO_STATE;
633 return status; 637 return status;
634 } 638 }
...@@ -671,10 +675,10 @@ folder_imap_lsub (folder_t folder, const char *ref, const char *name, ...@@ -671,10 +675,10 @@ folder_imap_lsub (folder_t folder, const char *ref, const char *name,
671 } 675 }
672 676
673 /* Build the folder list. */ 677 /* Build the folder list. */
674 if (f_imap->callback.flist.num > 0) 678 if (f_imap->flist.num > 0)
675 { 679 {
676 struct list_response **plist = NULL; 680 struct list_response **plist = NULL;
677 size_t num = f_imap->callback.flist.num; 681 size_t num = f_imap->flist.num;
678 size_t j = 0; 682 size_t j = 0;
679 plist = calloc (num, sizeof (*plist)); 683 plist = calloc (num, sizeof (*plist));
680 if (plist) 684 if (plist)
...@@ -682,7 +686,7 @@ folder_imap_lsub (folder_t folder, const char *ref, const char *name, ...@@ -682,7 +686,7 @@ folder_imap_lsub (folder_t folder, const char *ref, const char *name,
682 size_t i; 686 size_t i;
683 for (i = 0; i < num; i++) 687 for (i = 0; i < num; i++)
684 { 688 {
685 struct list_response *lr = f_imap->callback.flist.element[i]; 689 struct list_response *lr = f_imap->flist.element[i];
686 /* printf ("%s --> %s\n", lr->name, name); */ 690 /* printf ("%s --> %s\n", lr->name, name); */
687 plist[i] = calloc (1, sizeof (**plist)); 691 plist[i] = calloc (1, sizeof (**plist));
688 if (plist[i] == NULL 692 if (plist[i] == NULL
...@@ -697,7 +701,7 @@ folder_imap_lsub (folder_t folder, const char *ref, const char *name, ...@@ -697,7 +701,7 @@ folder_imap_lsub (folder_t folder, const char *ref, const char *name,
697 } 701 }
698 pflist->element = plist; 702 pflist->element = plist;
699 pflist->num = j; 703 pflist->num = j;
700 folder_list_destroy (&(f_imap->callback.flist)); 704 folder_list_destroy (&(f_imap->flist));
701 } 705 }
702 f_imap->state = IMAP_NO_STATE; 706 f_imap->state = IMAP_NO_STATE;
703 f_imap->state = IMAP_NO_STATE; 707 f_imap->state = IMAP_NO_STATE;
...@@ -811,8 +815,7 @@ folder_imap_unsubscribe (folder_t folder, const char *name) ...@@ -811,8 +815,7 @@ folder_imap_unsubscribe (folder_t folder, const char *name)
811 /* A literal is a sequence of zero or more octets (including CR and LF), 815 /* A literal is a sequence of zero or more octets (including CR and LF),
812 prefix-quoted with an octet count in the form of an open brace ("{"), 816 prefix-quoted with an octet count in the form of an open brace ("{"),
813 the number of octets, close brace ("}"), and CRLF. The sequence is read 817 the number of octets, close brace ("}"), and CRLF. The sequence is read
814 and put in the callback buffer, hopefully the callee did have enough 818 and put in the string buffer. */
815 room. */
816 static int 819 static int
817 imap_literal_string (f_imap_t f_imap, char **ptr) 820 imap_literal_string (f_imap_t f_imap, char **ptr)
818 { 821 {
...@@ -820,7 +823,7 @@ imap_literal_string (f_imap_t f_imap, char **ptr) ...@@ -820,7 +823,7 @@ imap_literal_string (f_imap_t f_imap, char **ptr)
820 int status = 0; 823 int status = 0;
821 int nl; 824 int nl;
822 /* The (len + 1) in the for is to count the strip '\r' by imap_readline. */ 825 /* The (len + 1) in the for is to count the strip '\r' by imap_readline. */
823 for (len0 = len = total = 0; total < f_imap->callback.nleft; total += (len + 1)) 826 for (len0 = len = total = 0; total < f_imap->string.nleft; total += (len + 1))
824 { 827 {
825 status = imap_readline (f_imap); 828 status = imap_readline (f_imap);
826 /*fprintf (stderr, "%d: %s", strlen (f_imap->buffer), f_imap->buffer);*/ 829 /*fprintf (stderr, "%d: %s", strlen (f_imap->buffer), f_imap->buffer);*/
...@@ -834,12 +837,12 @@ imap_literal_string (f_imap_t f_imap, char **ptr) ...@@ -834,12 +837,12 @@ imap_literal_string (f_imap_t f_imap, char **ptr)
834 /* How much ? */ 837 /* How much ? */
835 len0 = len = f_imap->nl - f_imap->buffer; 838 len0 = len = f_imap->nl - f_imap->buffer;
836 /* Check if the last read did not finish on a line, if yes do not copy in 839 /* Check if the last read did not finish on a line, if yes do not copy in
837 callback buffer the terminating sequence ")\r\n". We are doing this 840 string buffer the terminating sequence ")\r\n". We are doing this
838 by checking if the amount(total) we got so far + the len of the line 841 by checking if the amount(total) we got so far + the len of the line
839 +1 (taking to account the strip '\r') goes behond the request. */ 842 +1 (taking to account the strip '\r') goes behond the request. */
840 if ((total + len + 1) > f_imap->callback.nleft) 843 if ((total + len + 1) > f_imap->string.nleft)
841 { 844 {
842 len0 = len = f_imap->callback.nleft - total; 845 len0 = len = f_imap->string.nleft - total;
843 /* ALERT: if we ask for a substring, for example we have : 846 /* ALERT: if we ask for a substring, for example we have :
844 "123456\n", and ask for body[]<0.7> the server will send 847 "123456\n", and ask for body[]<0.7> the server will send
845 body[] {7} --> "123456\r". There was not enough space 848 body[] {7} --> "123456\r". There was not enough space
...@@ -848,35 +851,29 @@ imap_literal_string (f_imap_t f_imap, char **ptr) ...@@ -848,35 +851,29 @@ imap_literal_string (f_imap_t f_imap, char **ptr)
848 len0--; 851 len0--;
849 } 852 }
850 853
851 if (f_imap->callback.total < f_imap->callback.buflen) 854 stream_write (f_imap->string.stream, f_imap->buffer,
852 { 855 len0, f_imap->string.offset, NULL);
853 /* Check how much we can fill the callback buffer. */ 856 f_imap->string.offset += len0;
854 int x = (f_imap->callback.buflen - f_imap->callback.total) - len0;
855 x = (x >= 0) ? len0 : (x + len0);
856 if (f_imap->callback.buffer)
857 memcpy (f_imap->callback.buffer + f_imap->callback.total,
858 f_imap->buffer, x);
859 f_imap->callback.total += x;
860 857
861 /* Depending on the type of request we incremente the xxxx_lines 858 /* Depending on the type of request we incremente the xxxx_lines
862 and xxxx_sizes. */ 859 and xxxx_sizes. */
863 nl = (memchr (f_imap->buffer, '\n', len0)) ? 1 : 0; 860 nl = (memchr (f_imap->buffer, '\n', len0)) ? 1 : 0;
864 if (f_imap->callback.msg_imap) 861 if (f_imap->string.msg_imap)
865 { 862 {
866 switch (f_imap->callback.type) 863 switch (f_imap->string.type)
867 { 864 {
868 case IMAP_HEADER: 865 case IMAP_HEADER:
869 f_imap->callback.msg_imap->header_lines += nl; 866 f_imap->string.msg_imap->header_lines += nl;
870 f_imap->callback.msg_imap->header_size += x; 867 f_imap->string.msg_imap->header_size += len0;
871 break; 868 break;
872 869
873 case IMAP_BODY: 870 case IMAP_BODY:
874 f_imap->callback.msg_imap->body_lines += nl; 871 f_imap->string.msg_imap->body_lines += nl;
875 f_imap->callback.msg_imap->body_size += x; 872 f_imap->string.msg_imap->body_size += len0;
876 break; 873 break;
877 874
878 case IMAP_MESSAGE: 875 case IMAP_MESSAGE:
879 f_imap->callback.msg_imap->message_lines += nl; 876 f_imap->string.msg_imap->message_lines += nl;
880 /* The message size is known by sending RFC822.SIZE. */ 877 /* The message size is known by sending RFC822.SIZE. */
881 878
882 default: 879 default:
...@@ -884,9 +881,9 @@ imap_literal_string (f_imap_t f_imap, char **ptr) ...@@ -884,9 +881,9 @@ imap_literal_string (f_imap_t f_imap, char **ptr)
884 } 881 }
885 } 882 }
886 } 883 }
887 } 884 f_imap->string.nleft -= total;
888 f_imap->callback.nleft -= total; 885 /* We may have trailing junk like the closing ")\r\n" from a literal string
889 /* Move the command buffer, or do a full readline. */ 886 glob it by moving the command buffer, or doing a full readline. */
890 if (len == (size_t)(f_imap->nl - f_imap->buffer)) 887 if (len == (size_t)(f_imap->nl - f_imap->buffer))
891 { 888 {
892 len = 0; 889 len = 0;
...@@ -899,12 +896,14 @@ imap_literal_string (f_imap_t f_imap, char **ptr) ...@@ -899,12 +896,14 @@ imap_literal_string (f_imap_t f_imap, char **ptr)
899 /* A quoted string is a sequence of zero or more 7-bit characters, 896 /* A quoted string is a sequence of zero or more 7-bit characters,
900 excluding CR and LF, with double quote (<">) characters at each end. 897 excluding CR and LF, with double quote (<">) characters at each end.
901 Same thing as the literal, diferent format the result is put in the 898 Same thing as the literal, diferent format the result is put in the
902 callback buffer for the mailbox/callee. */ 899 string buffer for the mailbox/callee. */
903 static int 900 static int
904 imap_quoted_string (f_imap_t f_imap, char **ptr) 901 imap_quoted_string (f_imap_t f_imap, char **ptr)
905 { 902 {
906 char *bquote; 903 char *bquote;
907 int escaped = 0; 904 int escaped = 0;
905 size_t len;
906
908 (*ptr)++; 907 (*ptr)++;
909 bquote = *ptr; 908 bquote = *ptr;
910 while (**ptr && (**ptr != '"' || escaped)) 909 while (**ptr && (**ptr != '"' || escaped))
...@@ -912,23 +911,18 @@ imap_quoted_string (f_imap_t f_imap, char **ptr) ...@@ -912,23 +911,18 @@ imap_quoted_string (f_imap_t f_imap, char **ptr)
912 escaped = (**ptr == '\\') ? 1 : 0; 911 escaped = (**ptr == '\\') ? 1 : 0;
913 (*ptr)++; 912 (*ptr)++;
914 } 913 }
915 f_imap->callback.total = *ptr - bquote; 914
916 if (f_imap->callback.buffer) 915 len = *ptr - bquote;
917 free (f_imap->callback.buffer); 916 stream_write (f_imap->string.stream, bquote, len,
918 f_imap->callback.buffer = calloc (f_imap->callback.total + 1, 1); 917 f_imap->string.offset, NULL);
919 f_imap->callback.buflen = f_imap->callback.total; 918 f_imap->string.offset += len;
920 /* Fill the call back buffer. The if is redundant there should always
921 be enough room since the request is base on the buffer size. */
922 if (f_imap->callback.total <= f_imap->callback.buflen
923 && f_imap->callback.buffer)
924 memcpy (f_imap->callback.buffer, bquote, f_imap->callback.total);
925 if (**ptr == '"') 919 if (**ptr == '"')
926 (*ptr)++; 920 (*ptr)++;
927 return 0; 921 return 0;
928 } 922 }
929 923
930 /* Find which type of string the response is: literal or quoted and let the 924 /* Find which type of string the response is: literal or quoted and let the
931 function fill the callback buffer. */ 925 function fill the string buffer. */
932 static int 926 static int
933 imap_string (f_imap_t f_imap, char **ptr) 927 imap_string (f_imap_t f_imap, char **ptr)
934 { 928 {
...@@ -940,15 +934,11 @@ imap_string (f_imap_t f_imap, char **ptr) ...@@ -940,15 +934,11 @@ imap_string (f_imap_t f_imap, char **ptr)
940 switch (**ptr) 934 switch (**ptr)
941 { 935 {
942 case '{': 936 case '{':
943 f_imap->callback.nleft = strtol ((*ptr) + 1, ptr, 10); 937 f_imap->string.nleft = strtol ((*ptr) + 1, ptr, 10);
944 if (**ptr == '}') 938 if (**ptr == '}')
945 { 939 {
946 (*ptr)++; 940 (*ptr)++;
947 /* Reset the buffer to the beginning. */ 941 /* Reset the buffer to the beginning. */
948 if (f_imap->callback.buffer)
949 free (f_imap->callback.buffer);
950 f_imap->callback.buffer = calloc (f_imap->callback.nleft + 1, 1);
951 f_imap->callback.buflen = f_imap->callback.nleft;
952 f_imap->ptr = f_imap->buffer; 942 f_imap->ptr = f_imap->buffer;
953 status = imap_literal_string (f_imap, ptr); 943 status = imap_literal_string (f_imap, ptr);
954 } 944 }
...@@ -984,15 +974,15 @@ imap_list (f_imap_t f_imap) ...@@ -984,15 +974,15 @@ imap_list (f_imap_t f_imap)
984 buffer = alloca (len); 974 buffer = alloca (len);
985 memcpy (buffer, f_imap->buffer, len); 975 memcpy (buffer, f_imap->buffer, len);
986 buffer[len] = '\0'; 976 buffer[len] = '\0';
987 plr = realloc (f_imap->callback.flist.element, 977 plr = realloc (f_imap->flist.element,
988 (f_imap->callback.flist.num + 1) * sizeof (*plr)); 978 (f_imap->flist.num + 1) * sizeof (*plr));
989 if (plr == NULL) 979 if (plr == NULL)
990 return ENOMEM; 980 return ENOMEM;
991 f_imap->callback.flist.element = plr; 981 f_imap->flist.element = plr;
992 lr = plr[f_imap->callback.flist.num] = calloc (1, sizeof (*lr)); 982 lr = plr[f_imap->flist.num] = calloc (1, sizeof (*lr));
993 if (lr == NULL) 983 if (lr == NULL)
994 return ENOMEM; 984 return ENOMEM;
995 (f_imap->callback.flist.num)++; 985 (f_imap->flist.num)++;
996 986
997 /* Glob untag. */ 987 /* Glob untag. */
998 tok = strtok_r (buffer, " ", &sp); 988 tok = strtok_r (buffer, " ", &sp);
...@@ -1215,7 +1205,7 @@ imap_bodystructure0 (msg_imap_t msg_imap, char **ptr) ...@@ -1215,7 +1205,7 @@ imap_bodystructure0 (msg_imap_t msg_imap, char **ptr)
1215 static int 1205 static int
1216 imap_bodystructure (f_imap_t f_imap, char **ptr) 1206 imap_bodystructure (f_imap_t f_imap, char **ptr)
1217 { 1207 {
1218 return imap_bodystructure0 (f_imap->callback.msg_imap, ptr); 1208 return imap_bodystructure0 (f_imap->string.msg_imap, ptr);
1219 } 1209 }
1220 1210
1221 /* The Format for a FLAG response is : 1211 /* The Format for a FLAG response is :
...@@ -1241,10 +1231,10 @@ imap_bodystructure (f_imap_t f_imap, char **ptr) ...@@ -1241,10 +1231,10 @@ imap_bodystructure (f_imap_t f_imap, char **ptr)
1241 static int 1231 static int
1242 imap_flags (f_imap_t f_imap, char **ptr) 1232 imap_flags (f_imap_t f_imap, char **ptr)
1243 { 1233 {
1244 char *start_flag; 1234 char *start;
1245 char *end_flag; 1235 char *end;
1246 /* msg_imap may be null for an untag response deal with it. */ 1236 /* msg_imap may be null for an untag response deal with it. */
1247 msg_imap_t msg_imap = f_imap->callback.msg_imap; 1237 msg_imap_t msg_imap = f_imap->string.msg_imap;
1248 1238
1249 /* Skip space. */ 1239 /* Skip space. */
1250 while (**ptr == ' ') 1240 while (**ptr == ' ')
...@@ -1262,21 +1252,21 @@ imap_flags (f_imap_t f_imap, char **ptr) ...@@ -1262,21 +1252,21 @@ imap_flags (f_imap_t f_imap, char **ptr)
1262 (*ptr)++; 1252 (*ptr)++;
1263 1253
1264 /* Save the beginning of the word. */ 1254 /* Save the beginning of the word. */
1265 start_flag = *ptr; 1255 start = *ptr;
1266 1256
1267 /* Get the next word boundary. */ 1257 /* Get the next word boundary. */
1268 while (**ptr && **ptr != ' ' && **ptr != ')') 1258 while (**ptr && **ptr != ' ' && **ptr != ')')
1269 ++(*ptr); 1259 ++(*ptr);
1270 1260
1271 /* Make a C string for the strcasecmp. */ 1261 /* Make a C string for the strcasecmp. */
1272 end_flag = *ptr; 1262 end = *ptr;
1273 1263
1274 /* Bail out. */ 1264 /* Bail out. */
1275 if (*start_flag == '\0') 1265 if (*start == '\0')
1276 break; 1266 break;
1277 1267
1278 /* Guess the flag. */ 1268 /* Guess the flag. */
1279 if (strncasecmp (start_flag, "\\Seen", end_flag - start_flag) == 0) 1269 if (strncasecmp (start, "\\Seen", end - start) == 0)
1280 { 1270 {
1281 if (msg_imap) 1271 if (msg_imap)
1282 { 1272 {
...@@ -1286,28 +1276,28 @@ imap_flags (f_imap_t f_imap, char **ptr) ...@@ -1286,28 +1276,28 @@ imap_flags (f_imap_t f_imap, char **ptr)
1286 else 1276 else
1287 f_imap->flags |= MU_ATTRIBUTE_SEEN; 1277 f_imap->flags |= MU_ATTRIBUTE_SEEN;
1288 } 1278 }
1289 else if (strncasecmp (start_flag, "\\Answered", end_flag - start_flag) == 0) 1279 else if (strncasecmp (start, "\\Answered", end - start) == 0)
1290 { 1280 {
1291 if (msg_imap) 1281 if (msg_imap)
1292 msg_imap->flags |= MU_ATTRIBUTE_ANSWERED; 1282 msg_imap->flags |= MU_ATTRIBUTE_ANSWERED;
1293 else 1283 else
1294 f_imap->flags |= MU_ATTRIBUTE_ANSWERED; 1284 f_imap->flags |= MU_ATTRIBUTE_ANSWERED;
1295 } 1285 }
1296 else if (strncasecmp (start_flag, "\\Flagged", end_flag - start_flag) == 0) 1286 else if (strncasecmp (start, "\\Flagged", end - start) == 0)
1297 { 1287 {
1298 if (msg_imap) 1288 if (msg_imap)
1299 msg_imap->flags |= MU_ATTRIBUTE_FLAGGED; 1289 msg_imap->flags |= MU_ATTRIBUTE_FLAGGED;
1300 else 1290 else
1301 f_imap->flags |= MU_ATTRIBUTE_FLAGGED; 1291 f_imap->flags |= MU_ATTRIBUTE_FLAGGED;
1302 } 1292 }
1303 else if (strncasecmp (start_flag, "\\Deleted", end_flag - start_flag) == 0) 1293 else if (strncasecmp (start, "\\Deleted", end - start) == 0)
1304 { 1294 {
1305 if (msg_imap) 1295 if (msg_imap)
1306 msg_imap->flags |= MU_ATTRIBUTE_DELETED; 1296 msg_imap->flags |= MU_ATTRIBUTE_DELETED;
1307 else 1297 else
1308 f_imap->flags |= MU_ATTRIBUTE_DELETED; 1298 f_imap->flags |= MU_ATTRIBUTE_DELETED;
1309 } 1299 }
1310 else if (strncasecmp (start_flag, "\\Draft", end_flag - start_flag) == 0) 1300 else if (strncasecmp (start, "\\Draft", end - start) == 0)
1311 { 1301 {
1312 if (msg_imap) 1302 if (msg_imap)
1313 msg_imap->flags |= MU_ATTRIBUTE_DRAFT; 1303 msg_imap->flags |= MU_ATTRIBUTE_DRAFT;
...@@ -1343,20 +1333,20 @@ imap_body (f_imap_t f_imap, char **ptr) ...@@ -1343,20 +1333,20 @@ imap_body (f_imap_t f_imap, char **ptr)
1343 section[len] = '\0'; 1333 section[len] = '\0';
1344 /* strupper. */ 1334 /* strupper. */
1345 for (; *p; p++) if (isupper((unsigned)*p)) *p = toupper ((unsigned)*p); 1335 for (; *p; p++) if (isupper((unsigned)*p)) *p = toupper ((unsigned)*p);
1346 /* Set the callback type to update the correct line count. */ 1336 /* Set the string type to update the correct line count. */
1347 //if (!strstr (section, "FIELD")) 1337 //if (!strstr (section, "FIELD"))
1348 { 1338 {
1349 if (strstr (section, "MIME") || (strstr (section, "HEADER"))) 1339 if (strstr (section, "MIME") || (strstr (section, "HEADER")))
1350 { 1340 {
1351 f_imap->callback.type = IMAP_HEADER; 1341 f_imap->string.type = IMAP_HEADER;
1352 } 1342 }
1353 else if (strstr (section, "TEXT") || len > 0) 1343 else if (strstr (section, "TEXT") || len > 0)
1354 { 1344 {
1355 f_imap->callback.type = IMAP_BODY; 1345 f_imap->string.type = IMAP_BODY;
1356 } 1346 }
1357 else if (len == 0) /* body[] */ 1347 else if (len == 0) /* body[] */
1358 { 1348 {
1359 f_imap->callback.type = IMAP_MESSAGE; 1349 f_imap->string.type = IMAP_MESSAGE;
1360 } 1350 }
1361 } 1351 }
1362 sep++; /* Move pass the ']' */ 1352 sep++; /* Move pass the ']' */
...@@ -1379,16 +1369,19 @@ imap_body (f_imap_t f_imap, char **ptr) ...@@ -1379,16 +1369,19 @@ imap_body (f_imap_t f_imap, char **ptr)
1379 /* If the state scan. Catch it here. */ 1369 /* If the state scan. Catch it here. */
1380 if (f_imap->state == IMAP_SCAN_ACK) 1370 if (f_imap->state == IMAP_SCAN_ACK)
1381 { 1371 {
1382 if (f_imap->callback.msg_imap->fheader) 1372 char *buffer;
1383 header_destroy (&f_imap->callback.msg_imap->fheader, NULL); 1373 off_t total = 0;
1384 status = header_create (&f_imap->callback.msg_imap->fheader, 1374 if (f_imap->string.msg_imap && f_imap->string.msg_imap->fheader)
1385 f_imap->callback.buffer, f_imap->callback.total, 1375 header_destroy (&f_imap->string.msg_imap->fheader, NULL);
1386 NULL); 1376 stream_size (f_imap->string.stream, &total);
1387 free (f_imap->callback.buffer); 1377 buffer = malloc (total + 1);
1388 f_imap->callback.buffer = NULL; 1378 stream_read (f_imap->string.stream, buffer, total, 0, NULL);
1389 f_imap->callback.buflen = 0; 1379 status = header_create (&f_imap->string.msg_imap->fheader,
1390 f_imap->callback.total = 0; 1380 buffer, total, NULL);
1391 f_imap->callback.nleft = 0; 1381 free (buffer);
1382 stream_truncate (f_imap->string.stream, 0);
1383 f_imap->string.offset = 0;
1384 f_imap->string.nleft = 0;
1392 } 1385 }
1393 return status; 1386 return status;
1394 } 1387 }
...@@ -1404,8 +1397,8 @@ imap_uid (f_imap_t f_imap, char **ptr) ...@@ -1404,8 +1397,8 @@ imap_uid (f_imap_t f_imap, char **ptr)
1404 { 1397 {
1405 char token[128]; 1398 char token[128];
1406 imap_token (token, sizeof (token), ptr); 1399 imap_token (token, sizeof (token), ptr);
1407 if (f_imap->callback.msg_imap) 1400 if (f_imap->string.msg_imap)
1408 f_imap->callback.msg_imap->uid = strtoul (token, NULL, 10); 1401 f_imap->string.msg_imap->uid = strtoul (token, NULL, 10);
1409 return 0; 1402 return 0;
1410 } 1403 }
1411 1404
...@@ -1413,9 +1406,9 @@ static int ...@@ -1413,9 +1406,9 @@ static int
1413 imap_rfc822 (f_imap_t f_imap, char **ptr) 1406 imap_rfc822 (f_imap_t f_imap, char **ptr)
1414 { 1407 {
1415 int status; 1408 int status;
1416 f_imap->callback.type = IMAP_MESSAGE; 1409 f_imap->string.type = IMAP_MESSAGE;
1417 status = imap_body (f_imap, ptr); 1410 status = imap_body (f_imap, ptr);
1418 f_imap->callback.type = 0; 1411 f_imap->string.type = 0;
1419 return status; 1412 return status;
1420 } 1413 }
1421 1414
...@@ -1424,8 +1417,8 @@ imap_rfc822_size (f_imap_t f_imap, char **ptr) ...@@ -1424,8 +1417,8 @@ imap_rfc822_size (f_imap_t f_imap, char **ptr)
1424 { 1417 {
1425 char token[128]; 1418 char token[128];
1426 imap_token (token, sizeof (token), ptr); 1419 imap_token (token, sizeof (token), ptr);
1427 if (f_imap->callback.msg_imap) 1420 if (f_imap->string.msg_imap)
1428 f_imap->callback.msg_imap->message_size = strtoul (token, NULL, 10); 1421 f_imap->string.msg_imap->message_size = strtoul (token, NULL, 10);
1429 return 0; 1422 return 0;
1430 } 1423 }
1431 1424
...@@ -1433,9 +1426,9 @@ static int ...@@ -1433,9 +1426,9 @@ static int
1433 imap_rfc822_header (f_imap_t f_imap, char **ptr) 1426 imap_rfc822_header (f_imap_t f_imap, char **ptr)
1434 { 1427 {
1435 int status; 1428 int status;
1436 f_imap->callback.type = IMAP_HEADER; 1429 f_imap->string.type = IMAP_HEADER;
1437 status = imap_string (f_imap, ptr); 1430 status = imap_string (f_imap, ptr);
1438 f_imap->callback.type = 0; 1431 f_imap->string.type = 0;
1439 return status; 1432 return status;
1440 } 1433 }
1441 1434
...@@ -1443,9 +1436,9 @@ static int ...@@ -1443,9 +1436,9 @@ static int
1443 imap_rfc822_text (f_imap_t f_imap, char **ptr) 1436 imap_rfc822_text (f_imap_t f_imap, char **ptr)
1444 { 1437 {
1445 int status; 1438 int status;
1446 f_imap->callback.type = IMAP_HEADER; 1439 f_imap->string.type = IMAP_HEADER;
1447 status = imap_string (f_imap, ptr); 1440 status = imap_string (f_imap, ptr);
1448 f_imap->callback.type = 0; 1441 f_imap->string.type = 0;
1449 return status; 1442 return status;
1450 } 1443 }
1451 1444
...@@ -1493,8 +1486,8 @@ imap_fetch (f_imap_t f_imap) ...@@ -1493,8 +1486,8 @@ imap_fetch (f_imap_t f_imap)
1493 /* It is actually possible, but higly unlikely that we do not have the 1486 /* It is actually possible, but higly unlikely that we do not have the
1494 message yet, for example a "FETCH (FLAGS (\Recent))" notification 1487 message yet, for example a "FETCH (FLAGS (\Recent))" notification
1495 for a newly messsage. */ 1488 for a newly messsage. */
1496 if (f_imap->callback.msg_imap == NULL 1489 if (f_imap->string.msg_imap == NULL
1497 || f_imap->callback.msg_imap->num != msgno) 1490 || f_imap->string.msg_imap->num != msgno)
1498 { 1491 {
1499 /* Find the imap mesg struct. */ 1492 /* Find the imap mesg struct. */
1500 size_t i; 1493 size_t i;
...@@ -1504,7 +1497,7 @@ imap_fetch (f_imap_t f_imap) ...@@ -1504,7 +1497,7 @@ imap_fetch (f_imap_t f_imap)
1504 { 1497 {
1505 if (m_imap->imessages[i] && m_imap->imessages[i]->num == msgno) 1498 if (m_imap->imessages[i] && m_imap->imessages[i]->num == msgno)
1506 { 1499 {
1507 f_imap->callback.msg_imap = m_imap->imessages[i]; 1500 f_imap->string.msg_imap = m_imap->imessages[i];
1508 break; 1501 break;
1509 } 1502 }
1510 } 1503 }
...@@ -1767,6 +1760,7 @@ imap_parse (f_imap_t f_imap) ...@@ -1767,6 +1760,7 @@ imap_parse (f_imap_t f_imap)
1767 int done = 0; 1760 int done = 0;
1768 int status = 0; 1761 int status = 0;
1769 char empty[2]; 1762 char empty[2];
1763 char *buffer = NULL;
1770 1764
1771 /* We use that moronic hack to not check null for the tockenize strings. */ 1765 /* We use that moronic hack to not check null for the tockenize strings. */
1772 empty[0] = '\0'; 1766 empty[0] = '\0';
...@@ -1774,7 +1768,7 @@ imap_parse (f_imap_t f_imap) ...@@ -1774,7 +1768,7 @@ imap_parse (f_imap_t f_imap)
1774 while (! done) 1768 while (! done)
1775 { 1769 {
1776 char *tag, *response, *remainder; 1770 char *tag, *response, *remainder;
1777 char *buffer; 1771
1778 status = imap_readline (f_imap); 1772 status = imap_readline (f_imap);
1779 if (status != 0) 1773 if (status != 0)
1780 { 1774 {
...@@ -1787,17 +1781,24 @@ imap_parse (f_imap_t f_imap) ...@@ -1787,17 +1781,24 @@ imap_parse (f_imap_t f_imap)
1787 1781
1788 /* We do not want to step over f_imap->buffer since it can be use 1782 /* We do not want to step over f_imap->buffer since it can be use
1789 further down the chain. */ 1783 further down the chain. */
1790 buffer = alloca ((f_imap->ptr - f_imap->buffer) + 1); 1784 if (buffer)
1791 memcpy (buffer, f_imap->buffer, (f_imap->ptr - f_imap->buffer) + 1); 1785 {
1786 free (buffer);
1787 buffer = NULL;
1788 }
1789 buffer = calloc ((f_imap->ptr - f_imap->buffer) + 1, 1);
1790 memcpy (buffer, f_imap->buffer, (f_imap->ptr - f_imap->buffer));
1792 1791
1793 /* Tokenize the string. */ 1792 /* Tokenize the string. */
1794 { 1793 {
1795 char *sp = NULL; 1794 char *sp = NULL;
1796 tag = strtok_r (buffer, " ", &sp); 1795 tag = strtok_r (buffer, " ", &sp);
1797 response = strtok_r (NULL, " ", &sp); 1796 response = strtok_r (NULL, " ", &sp);
1798 if (!response) response = empty; 1797 if (!response)
1798 response = empty;
1799 remainder = strtok_r (NULL, "\n", &sp); 1799 remainder = strtok_r (NULL, "\n", &sp);
1800 if (!remainder) remainder = empty; 1800 if (!remainder)
1801 remainder = empty;
1801 } 1802 }
1802 1803
1803 /* Is the response untagged ? */ 1804 /* Is the response untagged ? */
...@@ -1831,6 +1832,7 @@ imap_parse (f_imap_t f_imap) ...@@ -1831,6 +1832,7 @@ imap_parse (f_imap_t f_imap)
1831 is not supported by this implementation. If the 1832 is not supported by this implementation. If the
1832 optional list of charsets is given, this lists the 1833 optional list of charsets is given, this lists the
1833 charsets that are supported by this implementation. */ 1834 charsets that are supported by this implementation. */
1835 mu_error ("BADCHARSET: %s\n", (sp) ? sp : "");
1834 } 1836 }
1835 else if (strcasecmp (subtag, "CAPABILITY") == 0) 1837 else if (strcasecmp (subtag, "CAPABILITY") == 0)
1836 { 1838 {
...@@ -1851,12 +1853,14 @@ imap_parse (f_imap_t f_imap) ...@@ -1851,12 +1853,14 @@ imap_parse (f_imap_t f_imap)
1851 mailbox name. This is a hint to the client that the 1853 mailbox name. This is a hint to the client that the
1852 operation can succeed if the SELECT or EXAMINE is 1854 operation can succeed if the SELECT or EXAMINE is
1853 reissued with the new mailbox name. */ 1855 reissued with the new mailbox name. */
1856 mu_error ("NEWNAME: %s\n", (sp) ? sp : "");
1854 } 1857 }
1855 else if (strcasecmp (subtag, "PARSE") == 0) 1858 else if (strcasecmp (subtag, "PARSE") == 0)
1856 { 1859 {
1857 /* The human-readable text represents an error in 1860 /* The human-readable text represents an error in
1858 parsing the [RFC-822] header or [MIME-IMB] headers 1861 parsing the [RFC-822] header or [MIME-IMB] headers
1859 of a message in the mailbox. */ 1862 of a message in the mailbox. */
1863 mu_error ("PARSE: %s\n", (sp) ? sp : "");
1860 } 1864 }
1861 else if (strcasecmp (subtag, "PERMANENTFLAGS") == 0) 1865 else if (strcasecmp (subtag, "PERMANENTFLAGS") == 0)
1862 { 1866 {
...@@ -1892,6 +1896,7 @@ imap_parse (f_imap_t f_imap) ...@@ -1892,6 +1896,7 @@ imap_parse (f_imap_t f_imap)
1892 other reason). This is a hint to the client that 1896 other reason). This is a hint to the client that
1893 the operation can succeed if the mailbox is first 1897 the operation can succeed if the mailbox is first
1894 created by the CREATE command. */ 1898 created by the CREATE command. */
1899 mu_error ("TRYCREATE: %s\n", (sp) ? sp : "");
1895 } 1900 }
1896 else if (strcasecmp (subtag, "UIDNEXT") == 0) 1901 else if (strcasecmp (subtag, "UIDNEXT") == 0)
1897 { 1902 {
...@@ -2031,5 +2036,8 @@ imap_parse (f_imap_t f_imap) ...@@ -2031,5 +2036,8 @@ imap_parse (f_imap_t f_imap)
2031 } 2036 }
2032 f_imap->ptr = f_imap->buffer; 2037 f_imap->ptr = f_imap->buffer;
2033 } 2038 }
2039
2040 if (buffer)
2041 free (buffer);
2034 return status; 2042 return status;
2035 } 2043 }
......
...@@ -140,10 +140,24 @@ struct _f_imap ...@@ -140,10 +140,24 @@ struct _f_imap
140 size_t seq; /* Sequence number to build a tag. */ 140 size_t seq; /* Sequence number to build a tag. */
141 char *capa; /* Cabilities of the server. */ 141 char *capa; /* Cabilities of the server. */
142 size_t flags; 142 size_t flags;
143 struct literal_string callback; 143
144 /* IO use to hold the literal and quoted strings send by
145 the IMAP server. */
146 struct
147 {
148 stream_t stream;
149 off_t offset;
150 size_t nleft; /* nleft to read in the literal. */
151 msg_imap_t msg_imap;
152 enum imap_state type;
153 } string;
154
155 /* Use for LIST and LSUB. */
156 struct folder_list flist;
144 157
145 int isopen; 158 int isopen;
146 /* Buffer I/O */ 159
160 /* Server channel buffer I/O */
147 size_t buflen; 161 size_t buflen;
148 char *buffer; 162 char *buffer;
149 char *ptr; 163 char *ptr;
...@@ -155,7 +169,6 @@ struct _f_imap ...@@ -155,7 +169,6 @@ struct _f_imap
155 /* Login */ 169 /* Login */
156 char *user; 170 char *user;
157 char *passwd; 171 char *passwd;
158
159 }; 172 };
160 173
161 struct _m_imap 174 struct _m_imap
...@@ -187,6 +200,7 @@ struct _msg_imap ...@@ -187,6 +200,7 @@ struct _msg_imap
187 size_t uid; 200 size_t uid;
188 201
189 header_t fheader; 202 header_t fheader;
203 char *internal_date;
190 204
191 size_t message_size; 205 size_t message_size;
192 size_t message_lines; 206 size_t message_lines;
......
...@@ -174,6 +174,8 @@ free_subparts (msg_imap_t msg_imap) ...@@ -174,6 +174,8 @@ free_subparts (msg_imap_t msg_imap)
174 free (msg_imap->parts); 174 free (msg_imap->parts);
175 if (msg_imap->fheader) 175 if (msg_imap->fheader)
176 header_destroy (&msg_imap->fheader, NULL); 176 header_destroy (&msg_imap->fheader, NULL);
177 if (msg_imap->internal_date)
178 free (msg_imap->internal_date);
177 free(msg_imap); 179 free(msg_imap);
178 } 180 }
179 181
...@@ -672,9 +674,15 @@ imap_expunge (mailbox_t mailbox) ...@@ -672,9 +674,15 @@ imap_expunge (mailbox_t mailbox)
672 { 674 {
673 case IMAP_NO_STATE: 675 case IMAP_NO_STATE:
674 { 676 {
675 char *set; 677 char *set = NULL;
676 status = delete_to_string (m_imap, &set); 678 status = delete_to_string (m_imap, &set);
677 CHECK_ERROR (f_imap, status); 679 CHECK_ERROR (f_imap, status);
680 if (set == NULL || *set == '\0')
681 {
682 if (set)
683 free (set);
684 return 0;
685 }
678 status = imap_writeline (f_imap, 686 status = imap_writeline (f_imap,
679 "g%d STORE %s +FLAGS.SILENT (\\Deleted)\r\n", 687 "g%d STORE %s +FLAGS.SILENT (\\Deleted)\r\n",
680 f_imap->seq++, set); 688 f_imap->seq++, set);
...@@ -1224,6 +1232,9 @@ imap_envelope_date (envelope_t envelope, char *buffer, size_t buflen, ...@@ -1224,6 +1232,9 @@ imap_envelope_date (envelope_t envelope, char *buffer, size_t buflen,
1224 const char** datep = &date; 1232 const char** datep = &date;
1225 /* reserve as much space as we need for internal-date */ 1233 /* reserve as much space as we need for internal-date */
1226 int status; 1234 int status;
1235
1236 if (msg_imap->internal_date == NULL)
1237 {
1227 if (f_imap->state == IMAP_NO_STATE) 1238 if (f_imap->state == IMAP_NO_STATE)
1228 { 1239 {
1229 /* Select first. */ 1240 /* Select first. */
...@@ -1237,9 +1248,17 @@ imap_envelope_date (envelope_t envelope, char *buffer, size_t buflen, ...@@ -1237,9 +1248,17 @@ imap_envelope_date (envelope_t envelope, char *buffer, size_t buflen,
1237 MAILBOX_DEBUG0 (m_imap->mailbox, MU_DEBUG_PROT, f_imap->buffer); 1248 MAILBOX_DEBUG0 (m_imap->mailbox, MU_DEBUG_PROT, f_imap->buffer);
1238 f_imap->state = IMAP_FETCH; 1249 f_imap->state = IMAP_FETCH;
1239 } 1250 }
1240 status = fetch_operation (f_imap, msg_imap, datebuf, sizeof datebuf, NULL); 1251 status = fetch_operation (f_imap, msg_imap, datebuf,
1252 sizeof datebuf, NULL);
1241 if (status != 0) 1253 if (status != 0)
1242 return status; 1254 return status;
1255 msg_imap->internal_date = strdup (datebuf);
1256 }
1257 else
1258 {
1259 date = msg_imap->internal_date;
1260 datep = &date;
1261 }
1243 1262
1244 if (mu_parse_imap_date_time(datep, &tm, &tz) != 0) 1263 if (mu_parse_imap_date_time(datep, &tm, &tz) != 0)
1245 now = (time_t)-1; 1264 now = (time_t)-1;
...@@ -1323,6 +1342,10 @@ imap_attr_set_flags (attribute_t attribute, int flag) ...@@ -1323,6 +1342,10 @@ imap_attr_set_flags (attribute_t attribute, int flag)
1323 f_imap_t f_imap = m_imap->f_imap; 1342 f_imap_t f_imap = m_imap->f_imap;
1324 int status = 0; 1343 int status = 0;
1325 1344
1345 /* If already set don't bother. */
1346 if (msg_imap->flags & flag)
1347 return 0;
1348
1326 /* The delete FLAG is not pass yet but only on the expunge. */ 1349 /* The delete FLAG is not pass yet but only on the expunge. */
1327 if (flag & MU_ATTRIBUTE_DELETED) 1350 if (flag & MU_ATTRIBUTE_DELETED)
1328 { 1351 {
...@@ -1705,13 +1728,11 @@ fetch_operation (f_imap_t f_imap, msg_imap_t msg_imap, char *buffer, ...@@ -1705,13 +1728,11 @@ fetch_operation (f_imap_t f_imap, msg_imap_t msg_imap, char *buffer,
1705 case IMAP_FETCH: 1728 case IMAP_FETCH:
1706 status = imap_send (f_imap); 1729 status = imap_send (f_imap);
1707 CHECK_EAGAIN (f_imap, status); 1730 CHECK_EAGAIN (f_imap, status);
1708 if (f_imap->callback.buffer) 1731 stream_truncate (f_imap->string.stream, 0);
1709 free (f_imap->callback.buffer); 1732 f_imap->string.offset = 0;
1710 f_imap->callback.buffer = NULL; 1733 f_imap->string.nleft = 0;
1711 f_imap->callback.buflen = 0; 1734 f_imap->string.type = IMAP_NO_STATE;
1712 f_imap->callback.total = 0; 1735 f_imap->string.msg_imap = msg_imap;
1713 f_imap->callback.nleft = 0;
1714 f_imap->callback.msg_imap = msg_imap;
1715 f_imap->state = IMAP_FETCH_ACK; 1736 f_imap->state = IMAP_FETCH_ACK;
1716 1737
1717 case IMAP_FETCH_ACK: 1738 case IMAP_FETCH_ACK:
...@@ -1725,25 +1746,21 @@ fetch_operation (f_imap_t f_imap, msg_imap_t msg_imap, char *buffer, ...@@ -1725,25 +1746,21 @@ fetch_operation (f_imap_t f_imap, msg_imap_t msg_imap, char *buffer,
1725 break; 1746 break;
1726 } 1747 }
1727 1748
1728 if (status == 0 && f_imap->isopen == 0 && f_imap->callback.total == 0) 1749 f_imap->state = IMAP_NO_STATE;
1750
1751 /* The server may have timeout any case connection is gone away. */
1752 if (status == 0 && f_imap->isopen == 0 && f_imap->string.offset == 0)
1729 status = EBADF; 1753 status = EBADF;
1730 1754
1731 buflen = min (buflen, f_imap->callback.total);
1732 if (f_imap->callback.buffer)
1733 {
1734 if (buffer) 1755 if (buffer)
1735 memcpy (buffer, f_imap->callback.buffer, buflen); 1756 stream_read (f_imap->string.stream, buffer, buflen, 0, plen);
1736 free (f_imap->callback.buffer); 1757 else if (plen)
1737 } 1758 *plen = 0;
1738 if (plen) 1759 stream_truncate (f_imap->string.stream, 0);
1739 *plen = buflen; 1760 f_imap->string.offset = 0;
1740 f_imap->callback.buffer = NULL; 1761 f_imap->string.nleft = 0;
1741 f_imap->callback.buflen = 0; 1762 f_imap->string.type = IMAP_NO_STATE;
1742 f_imap->callback.total = 0; 1763 f_imap->string.msg_imap = NULL;
1743 f_imap->callback.nleft = 0;
1744 f_imap->callback.type = 0;
1745 f_imap->callback.msg_imap = NULL;
1746 f_imap->state = IMAP_NO_STATE;
1747 return status; 1764 return status;
1748 } 1765 }
1749 1766
......
...@@ -22,15 +22,24 @@ ...@@ -22,15 +22,24 @@
22 #include <errno.h> 22 #include <errno.h>
23 #include <stdlib.h> 23 #include <stdlib.h>
24 #include <string.h> 24 #include <string.h>
25 #include <sys/stat.h>
26 #include <unistd.h>
27 #include <stdio.h>
25 28
26 #include <sys/types.h> 29 #include <sys/types.h>
27 30
28 #include <mailutils/stream.h> 31 #include <mailutils/stream.h>
29 32
33 #undef min
34 #define min(a,b) ((a) < (b) ? (a) : (b))
35
36 #define MU_STREAM_MEMORY_BLOCKSIZE 128
37
30 struct _memory_stream 38 struct _memory_stream
31 { 39 {
32 char *ptr; 40 char *ptr;
33 size_t size; 41 size_t size;
42 size_t capacity;
34 }; 43 };
35 44
36 static void 45 static void
...@@ -71,7 +80,7 @@ _memory_readline (stream_t stream, char *optr, size_t osize, ...@@ -71,7 +80,7 @@ _memory_readline (stream_t stream, char *optr, size_t osize,
71 osize--; 80 osize--;
72 nl = memchr (mfs->ptr + offset, '\n', mfs->size - offset); 81 nl = memchr (mfs->ptr + offset, '\n', mfs->size - offset);
73 n = (nl) ? (size_t)(nl - (mfs->ptr + offset) + 1) : mfs->size - offset; 82 n = (nl) ? (size_t)(nl - (mfs->ptr + offset) + 1) : mfs->size - offset;
74 n = (n > osize) ? osize : n; 83 n = min (n, osize);
75 memcpy (optr, mfs->ptr + offset, n); 84 memcpy (optr, mfs->ptr + offset, n);
76 optr[n] = '\0'; 85 optr[n] = '\0';
77 } 86 }
...@@ -87,13 +96,17 @@ _memory_write (stream_t stream, const char *iptr, size_t isize, ...@@ -87,13 +96,17 @@ _memory_write (stream_t stream, const char *iptr, size_t isize,
87 struct _memory_stream *mfs = stream_get_owner (stream); 96 struct _memory_stream *mfs = stream_get_owner (stream);
88 97
89 /* Bigger we have to realloc. */ 98 /* Bigger we have to realloc. */
90 if (mfs->size < (offset + isize)) 99 if (mfs->capacity < (offset + isize))
91 { 100 {
92 char *tmp = realloc (mfs->ptr, offset + isize); 101 /* Realloc by fixed blocks of 128. */
102 int newsize = MU_STREAM_MEMORY_BLOCKSIZE *
103 (((offset + isize)/MU_STREAM_MEMORY_BLOCKSIZE) + 1);
104 char *tmp = realloc (mfs->ptr, newsize);
93 if (tmp == NULL) 105 if (tmp == NULL)
94 return ENOMEM; 106 return ENOMEM;
95 mfs->ptr = tmp; 107 mfs->ptr = tmp;
96 mfs->size = offset + isize; 108 mfs->size = offset + isize;
109 mfs->capacity = newsize;
97 } 110 }
98 111
99 memcpy (mfs->ptr + offset, iptr, isize); 112 memcpy (mfs->ptr + offset, iptr, isize);
...@@ -109,6 +122,7 @@ _memory_truncate (stream_t stream, off_t len) ...@@ -109,6 +122,7 @@ _memory_truncate (stream_t stream, off_t len)
109 122
110 if (len == 0) 123 if (len == 0)
111 { 124 {
125 if (mfs->ptr)
112 free (mfs->ptr); 126 free (mfs->ptr);
113 mfs->ptr = NULL; 127 mfs->ptr = NULL;
114 } 128 }
...@@ -120,6 +134,7 @@ _memory_truncate (stream_t stream, off_t len) ...@@ -120,6 +134,7 @@ _memory_truncate (stream_t stream, off_t len)
120 mfs->ptr = tmp; 134 mfs->ptr = tmp;
121 } 135 }
122 mfs->size = len; 136 mfs->size = len;
137 mfs->capacity = len;
123 return 0; 138 return 0;
124 } 139 }
125 140
...@@ -137,11 +152,10 @@ _memory_close (stream_t stream) ...@@ -137,11 +152,10 @@ _memory_close (stream_t stream)
137 { 152 {
138 struct _memory_stream *mfs = stream_get_owner (stream); 153 struct _memory_stream *mfs = stream_get_owner (stream);
139 if (mfs->ptr) 154 if (mfs->ptr)
140 {
141 free (mfs->ptr); 155 free (mfs->ptr);
142 mfs->ptr = NULL; 156 mfs->ptr = NULL;
143 mfs->size = 0; 157 mfs->size = 0;
144 } 158 mfs->capacity = 0;
145 return 0; 159 return 0;
146 } 160 }
147 161
...@@ -149,6 +163,7 @@ static int ...@@ -149,6 +163,7 @@ static int
149 _memory_open (stream_t stream, const char *filename, int port, int flags) 163 _memory_open (stream_t stream, const char *filename, int port, int flags)
150 { 164 {
151 struct _memory_stream *mfs = stream_get_owner (stream); 165 struct _memory_stream *mfs = stream_get_owner (stream);
166 int status = 0;
152 167
153 (void)port; /* Ignored. */ 168 (void)port; /* Ignored. */
154 (void)filename; /* Ignored. */ 169 (void)filename; /* Ignored. */
...@@ -156,13 +171,47 @@ _memory_open (stream_t stream, const char *filename, int port, int flags) ...@@ -156,13 +171,47 @@ _memory_open (stream_t stream, const char *filename, int port, int flags)
156 171
157 /* Close any previous file. */ 172 /* Close any previous file. */
158 if (mfs->ptr) 173 if (mfs->ptr)
174 free (mfs->ptr);
175 mfs->ptr = NULL;
176 mfs->size = 0;
177 mfs->capacity = 0;
178 stream_set_flags (stream, flags |MU_STREAM_NO_CHECK);
179 if (filename)
180 {
181 struct stat statbuf;
182 if (stat (filename, &statbuf) == 0)
183 {
184 mfs->ptr = calloc (statbuf.st_size, 1);
185 if (mfs->ptr)
186 {
187 FILE *fp;
188 mfs->capacity = statbuf.st_size;
189 mfs->size = statbuf.st_size;
190 fp = fopen (filename, "r");
191 if (fp)
192 {
193 size_t r = fread (mfs->ptr, mfs->size, 1, fp);
194 if (r != mfs->size)
195 status = EIO;
196 fclose (fp);
197 }
198 else
199 status = errno;
200 if (status != 0)
159 { 201 {
160 free (mfs->ptr); 202 free (mfs->ptr);
161 mfs->ptr = NULL; 203 mfs->ptr = NULL;
204 mfs->capacity = 0;
162 mfs->size = 0; 205 mfs->size = 0;
163 } 206 }
164 stream_set_flags (stream, flags |MU_STREAM_NO_CHECK); 207 }
165 return 0; 208 else
209 status = ENOMEM;
210 }
211 else
212 status = EIO;
213 }
214 return status;
166 } 215 }
167 216
168 int 217 int
......
...@@ -60,8 +60,7 @@ _stream_memory_read (stream_t stream, void *optr, size_t osize, ...@@ -60,8 +60,7 @@ _stream_memory_read (stream_t stream, void *optr, size_t osize,
60 mu_refcount_lock (mem->refcount); 60 mu_refcount_lock (mem->refcount);
61 if (mem->ptr != NULL && (offset < (off_t)mem->size)) 61 if (mem->ptr != NULL && (offset < (off_t)mem->size))
62 { 62 {
63 n = ((offset + osize) > mem->size) ? 63 n = ((offset + osize) > mem->size) ? mem->size - offset : osize;
64 mem->size - offset : osize;
65 memcpy (optr, mem->ptr + offset, n); 64 memcpy (optr, mem->ptr + offset, n);
66 } 65 }
67 mu_refcount_unlock (mem->refcount); 66 mu_refcount_unlock (mem->refcount);
...@@ -130,6 +129,7 @@ _stream_memory_truncate (stream_t stream, off_t len) ...@@ -130,6 +129,7 @@ _stream_memory_truncate (stream_t stream, off_t len)
130 mu_refcount_lock (mem->refcount); 129 mu_refcount_lock (mem->refcount);
131 if (len == 0) 130 if (len == 0)
132 { 131 {
132 if (mem->ptr)
133 free (mem->ptr); 133 free (mem->ptr);
134 mem->ptr = NULL; 134 mem->ptr = NULL;
135 } 135 }
......