]> mj.ucw.cz Git - umpf.git/blob - ham.c
really do local delivery
[umpf.git] / ham.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4
5 #include <unistd.h>
6
7 #include "umpf.h"
8
9 int curbufsize;
10
11 char mbox_write_buf[BUFSIZE];
12 int mbox_write_pos;
13 int mbox_write_err;
14
15 static void
16 new_header(char* buf, struct list* h)
17 {
18         char* p;
19         struct hlist* new;
20
21         new = xmalloc(sizeof(struct hlist));
22
23         p = strchr(buf, ':');
24         if (!p)
25                 new->value = xstrdup("");
26         else {
27                 *p = 0;
28                 new->value = xstrdup(p+1);
29                 p = strrchr(new->value, '\n');
30                 if (p && !*(p+1))
31                         *p = 0;
32         }
33         new->name = xstrdup(buf);
34
35         list_add_last(h, &new->car);
36 }
37
38 struct list*
39 make_hlist(void)
40 {
41         struct list* l = xmalloc(sizeof(struct list));
42         char* buf;
43         int i = 0; /* current position */
44         int c, last = 0;
45
46         list_init(l);
47         buf = xmalloc(BUFSIZE);
48         curbufsize = BUFSIZE;
49         
50         while ((c = getchar()) != EOF){
51                 if (c == '\r')
52                         continue;
53
54                 if (i >= curbufsize-2)
55                         buf = xrealloc(buf, curbufsize *= 2);
56                 
57                 buf[i++] = c; 
58                 if (c == '\n'){
59                         if (last == '\n')
60                                 break;
61                         if ((c = getchar()) != ' ' && c != '\t'){
62                                 if (c != EOF)
63                                         ungetc(c, stdin);
64                                 buf[i] = 0;
65                                 new_header(buf, l);
66                                 i = 0;
67                         } else
68                                 buf[i++] = c;
69                 }
70                         last = c;
71         }
72         free(buf);
73         return l;
74 }
75
76 struct email*
77 get_body(void)
78 {
79         char* buf;
80         struct email* b;
81         int c;
82         int i = 0;
83         int curbufsize = BUFSIZE;
84
85         buf = xmalloc(BUFSIZE);
86         while ((c = getchar()) != EOF){
87                 buf[i++] = c;
88
89                 if (i >= curbufsize - 1)
90                         buf = xrealloc(buf, curbufsize *= 2);
91         }
92
93         b = xmalloc(sizeof(struct email));
94         b->body = buf;
95         b->body_len = i;
96
97         return b; 
98 }
99
100 void
101 print_headers(struct list* l)
102 {
103         struct hlist* p;
104
105         LIST_FOREACH(p,l)
106                 printf("%s:%s\n",p->name,p->value);
107 }
108
109 static void
110 flush_mbox_buffer(int fd)
111 {
112         if (mbox_write_err || !mbox_write_pos)
113                 return;
114
115         int res;
116         res = write(fd, mbox_write_buf, mbox_write_pos);
117         if (res < 0)
118                 mbox_write_err++;
119         mbox_write_pos = 0;
120 }
121
122 static void
123 write_char_to_mailbox(char c, int fd)
124 {
125         int res;
126
127         if (mbox_write_pos >= BUFSIZE){
128                 res = write(fd, mbox_write_buf, BUFSIZE);
129                 if (res < 0)
130                         mbox_write_err++;
131                 mbox_write_pos = 0;
132                 return;
133         }
134         mbox_write_buf[mbox_write_pos++] = c;
135 }
136
137 /* try to copy e-mail to mailbox, if it fails,
138  truncate mailbox to the original size */
139 static int
140 copy_email(int fd, struct email* email)
141 {
142         off_t mb_end;
143
144         mb_end = lseek(fd, 0, SEEK_END);
145         if (mb_end < 0)
146                 return -1;
147
148         /* init globals */
149         mbox_write_err = 0;
150         mbox_write_pos = 0;
151
152         /* headers */
153         struct hlist* ph;
154         char* pc;
155         LIST_FOREACH(ph, email->headers){
156                 for (pc = ph->name; *pc; pc++)
157                         write_char_to_mailbox(*pc, fd);
158                 write_char_to_mailbox(':', fd); 
159                 write_char_to_mailbox(' ', fd); 
160                 for (pc = ph->value; *pc; pc++)
161                         write_char_to_mailbox(*pc, fd); 
162                         write_char_to_mailbox('\n', fd);        
163         }
164
165         write_char_to_mailbox('\n', fd);
166         /* body */
167         /* FIXME: do not forget change Content-Length */
168         for (pc = email->body; pc < email->body + email->body_len; pc++){
169                         write_char_to_mailbox(*pc, fd);
170                         if (*pc == '\n'){
171                                 if ((pc + 5 < email->body + email->body_len)
172                                         && pc[1] == 'F' && pc[2] == 'r'
173                                         && pc[3] == 'o' && pc[4] == 'm'
174                                         && pc[5] == ' ')
175                                 write_char_to_mailbox('>', fd); 
176                         }
177         }       
178
179         flush_mbox_buffer(fd);
180
181         /* errors? */
182         if (mbox_write_err){
183                 /* try to truncate to the original length */
184                 ftruncate(fd, mb_end);  
185                 return -1;
186         }       
187
188         return 0; 
189 }
190
191 int
192 deliver_local_email(char* folder, struct email* email)
193 {
194         int res = -1;
195         int is_default_mailbox = 0;
196         int fd;
197
198         if (!strcmp(default_mailbox, folder))   
199                 is_default_mailbox = 1;
200
201         fd = open_mailbox(folder, is_default_mailbox);
202         if (fd < 0){
203                 if (is_default_mailbox)
204                         return res;
205                 else /* try to save to default mailbox instead */
206                         return deliver_local_email(default_mailbox, email);
207         }
208
209         res = copy_email(fd, email);
210         if (res < 0){
211
212                 /* try to deliver to the default mailbox */
213                 if (is_default_mailbox)
214                         return res;
215                 else
216                         return deliver_local_email(default_mailbox, email);
217         }
218
219         close_mailbox(fd, folder, is_default_mailbox);  
220
221         return res; 
222 }