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