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