Blame


1 5cdb1798 2005-10-29 devnull /*
2 5cdb1798 2005-10-29 devnull * this is a filter that changes mime types and names of
3 5cdb1798 2005-10-29 devnull * suspect executable attachments.
4 5cdb1798 2005-10-29 devnull */
5 5cdb1798 2005-10-29 devnull #include "common.h"
6 5cdb1798 2005-10-29 devnull #include <ctype.h>
7 20bd3ca2 2006-04-09 devnull
8 20bd3ca2 2006-04-09 devnull enum {
9 20bd3ca2 2006-04-09 devnull Accept = 0xA,
10 20bd3ca2 2006-04-09 devnull Discard = 0xD,
11 20bd3ca2 2006-04-09 devnull };
12 5cdb1798 2005-10-29 devnull
13 5cdb1798 2005-10-29 devnull Biobuf in;
14 5cdb1798 2005-10-29 devnull Biobuf out;
15 5cdb1798 2005-10-29 devnull
16 5cdb1798 2005-10-29 devnull typedef struct Mtype Mtype;
17 5cdb1798 2005-10-29 devnull typedef struct Hdef Hdef;
18 5cdb1798 2005-10-29 devnull typedef struct Hline Hline;
19 5cdb1798 2005-10-29 devnull typedef struct Part Part;
20 5cdb1798 2005-10-29 devnull
21 5cdb1798 2005-10-29 devnull static int badfile(char *name);
22 5cdb1798 2005-10-29 devnull static int badtype(char *type);
23 5cdb1798 2005-10-29 devnull static void ctype(Part*, Hdef*, char*);
24 5cdb1798 2005-10-29 devnull static void cencoding(Part*, Hdef*, char*);
25 5cdb1798 2005-10-29 devnull static void cdisposition(Part*, Hdef*, char*);
26 5cdb1798 2005-10-29 devnull static int decquoted(char *out, char *in, char *e);
27 5cdb1798 2005-10-29 devnull static char* getstring(char *p, String *s, int dolower);
28 5cdb1798 2005-10-29 devnull static void init_hdefs(void);
29 5cdb1798 2005-10-29 devnull static int isattribute(char **pp, char *attr);
30 5cdb1798 2005-10-29 devnull static int latin1toutf(char *out, char *in, char *e);
31 5cdb1798 2005-10-29 devnull static String* mkboundary(void);
32 5cdb1798 2005-10-29 devnull static Part* part(Part *pp);
33 5cdb1798 2005-10-29 devnull static Part* passbody(Part *p, int dobound);
34 5cdb1798 2005-10-29 devnull static void passnotheader(void);
35 5cdb1798 2005-10-29 devnull static void passunixheader(void);
36 5cdb1798 2005-10-29 devnull static Part* problemchild(Part *p);
37 5cdb1798 2005-10-29 devnull static void readheader(Part *p);
38 5cdb1798 2005-10-29 devnull static Hline* readhl(void);
39 5cdb1798 2005-10-29 devnull static void readmtypes(void);
40 5cdb1798 2005-10-29 devnull static int save(Part *p, char *file);
41 5cdb1798 2005-10-29 devnull static void setfilename(Part *p, char *name);
42 5cdb1798 2005-10-29 devnull static char* skiptosemi(char *p);
43 5cdb1798 2005-10-29 devnull static char* skipwhite(char *p);
44 5cdb1798 2005-10-29 devnull static String* tokenconvert(String *t);
45 5cdb1798 2005-10-29 devnull static void writeheader(Part *p, int);
46 5cdb1798 2005-10-29 devnull
47 5cdb1798 2005-10-29 devnull enum
48 5cdb1798 2005-10-29 devnull {
49 cbeb0b26 2006-04-01 devnull /* encodings */
50 5cdb1798 2005-10-29 devnull Enone= 0,
51 5cdb1798 2005-10-29 devnull Ebase64,
52 5cdb1798 2005-10-29 devnull Equoted,
53 5cdb1798 2005-10-29 devnull
54 cbeb0b26 2006-04-01 devnull /* disposition possibilities */
55 5cdb1798 2005-10-29 devnull Dnone= 0,
56 5cdb1798 2005-10-29 devnull Dinline,
57 5cdb1798 2005-10-29 devnull Dfile,
58 5cdb1798 2005-10-29 devnull Dignore,
59 5cdb1798 2005-10-29 devnull
60 cbeb0b26 2006-04-01 devnull PAD64= '='
61 5cdb1798 2005-10-29 devnull };
62 5cdb1798 2005-10-29 devnull
63 5cdb1798 2005-10-29 devnull /*
64 5cdb1798 2005-10-29 devnull * a message part; either the whole message or a subpart
65 5cdb1798 2005-10-29 devnull */
66 5cdb1798 2005-10-29 devnull struct Part
67 5cdb1798 2005-10-29 devnull {
68 5cdb1798 2005-10-29 devnull Part *pp; /* parent part */
69 5cdb1798 2005-10-29 devnull Hline *hl; /* linked list of header lines */
70 5cdb1798 2005-10-29 devnull int disposition;
71 5cdb1798 2005-10-29 devnull int encoding;
72 5cdb1798 2005-10-29 devnull int badfile;
73 5cdb1798 2005-10-29 devnull int badtype;
74 5cdb1798 2005-10-29 devnull String *boundary; /* boundary for multiparts */
75 5cdb1798 2005-10-29 devnull int blen;
76 5cdb1798 2005-10-29 devnull String *charset; /* character set */
77 5cdb1798 2005-10-29 devnull String *type; /* content type */
78 5cdb1798 2005-10-29 devnull String *filename; /* file name */
79 5cdb1798 2005-10-29 devnull Biobuf *tmpbuf; /* diversion input buffer */
80 5cdb1798 2005-10-29 devnull };
81 5cdb1798 2005-10-29 devnull
82 5cdb1798 2005-10-29 devnull /*
83 5cdb1798 2005-10-29 devnull * a (multi)line header
84 5cdb1798 2005-10-29 devnull */
85 5cdb1798 2005-10-29 devnull struct Hline
86 5cdb1798 2005-10-29 devnull {
87 5cdb1798 2005-10-29 devnull Hline *next;
88 5cdb1798 2005-10-29 devnull String *s;
89 5cdb1798 2005-10-29 devnull };
90 5cdb1798 2005-10-29 devnull
91 5cdb1798 2005-10-29 devnull /*
92 5cdb1798 2005-10-29 devnull * header definitions for parsing
93 5cdb1798 2005-10-29 devnull */
94 5cdb1798 2005-10-29 devnull struct Hdef
95 5cdb1798 2005-10-29 devnull {
96 5cdb1798 2005-10-29 devnull char *type;
97 5cdb1798 2005-10-29 devnull void (*f)(Part*, Hdef*, char*);
98 5cdb1798 2005-10-29 devnull int len;
99 5cdb1798 2005-10-29 devnull };
100 5cdb1798 2005-10-29 devnull
101 5cdb1798 2005-10-29 devnull Hdef hdefs[] =
102 5cdb1798 2005-10-29 devnull {
103 5cdb1798 2005-10-29 devnull { "content-type:", ctype, },
104 5cdb1798 2005-10-29 devnull { "content-transfer-encoding:", cencoding, },
105 5cdb1798 2005-10-29 devnull { "content-disposition:", cdisposition, },
106 cbeb0b26 2006-04-01 devnull { 0, }
107 5cdb1798 2005-10-29 devnull };
108 5cdb1798 2005-10-29 devnull
109 5cdb1798 2005-10-29 devnull /*
110 5cdb1798 2005-10-29 devnull * acceptable content types and their extensions
111 5cdb1798 2005-10-29 devnull */
112 5cdb1798 2005-10-29 devnull struct Mtype {
113 5cdb1798 2005-10-29 devnull Mtype *next;
114 5cdb1798 2005-10-29 devnull char *ext; /* extension */
115 5cdb1798 2005-10-29 devnull char *gtype; /* generic content type */
116 5cdb1798 2005-10-29 devnull char *stype; /* specific content type */
117 5cdb1798 2005-10-29 devnull char class;
118 5cdb1798 2005-10-29 devnull };
119 5cdb1798 2005-10-29 devnull Mtype *mtypes;
120 5cdb1798 2005-10-29 devnull
121 5cdb1798 2005-10-29 devnull int justreject;
122 5cdb1798 2005-10-29 devnull char *savefile;
123 5cdb1798 2005-10-29 devnull
124 5cdb1798 2005-10-29 devnull void
125 b5f65921 2006-02-11 devnull usage(void)
126 b5f65921 2006-02-11 devnull {
127 b5f65921 2006-02-11 devnull fprint(2, "usage: upas/vf [-r] [-s savefile]\n");
128 b5f65921 2006-02-11 devnull exits("usage");
129 b5f65921 2006-02-11 devnull }
130 b5f65921 2006-02-11 devnull
131 b5f65921 2006-02-11 devnull void
132 5cdb1798 2005-10-29 devnull main(int argc, char **argv)
133 5cdb1798 2005-10-29 devnull {
134 5cdb1798 2005-10-29 devnull ARGBEGIN{
135 5cdb1798 2005-10-29 devnull case 'r':
136 5cdb1798 2005-10-29 devnull justreject = 1;
137 5cdb1798 2005-10-29 devnull break;
138 5cdb1798 2005-10-29 devnull case 's':
139 b5f65921 2006-02-11 devnull savefile = EARGF(usage());
140 5cdb1798 2005-10-29 devnull break;
141 b5f65921 2006-02-11 devnull default:
142 b5f65921 2006-02-11 devnull usage();
143 5cdb1798 2005-10-29 devnull }ARGEND;
144 b5f65921 2006-02-11 devnull
145 b5f65921 2006-02-11 devnull if(argc)
146 b5f65921 2006-02-11 devnull usage();
147 5cdb1798 2005-10-29 devnull
148 5cdb1798 2005-10-29 devnull Binit(&in, 0, OREAD);
149 5cdb1798 2005-10-29 devnull Binit(&out, 1, OWRITE);
150 5cdb1798 2005-10-29 devnull
151 5cdb1798 2005-10-29 devnull init_hdefs();
152 5cdb1798 2005-10-29 devnull readmtypes();
153 5cdb1798 2005-10-29 devnull
154 5cdb1798 2005-10-29 devnull /* pass through our standard 'From ' line */
155 5cdb1798 2005-10-29 devnull passunixheader();
156 5cdb1798 2005-10-29 devnull
157 5cdb1798 2005-10-29 devnull /* parse with the top level part */
158 5cdb1798 2005-10-29 devnull part(nil);
159 5cdb1798 2005-10-29 devnull
160 5cdb1798 2005-10-29 devnull exits(0);
161 5cdb1798 2005-10-29 devnull }
162 5cdb1798 2005-10-29 devnull
163 5cdb1798 2005-10-29 devnull void
164 5cdb1798 2005-10-29 devnull refuse(void)
165 5cdb1798 2005-10-29 devnull {
166 5cdb1798 2005-10-29 devnull postnote(PNGROUP, getpid(), "mail refused: we don't accept executable attachments");
167 5cdb1798 2005-10-29 devnull exits("mail refused: we don't accept executable attachments");
168 5cdb1798 2005-10-29 devnull }
169 5cdb1798 2005-10-29 devnull
170 5cdb1798 2005-10-29 devnull
171 5cdb1798 2005-10-29 devnull /*
172 5cdb1798 2005-10-29 devnull * parse a part; returns the ancestor whose boundary terminated
173 5cdb1798 2005-10-29 devnull * this part or nil on EOF.
174 5cdb1798 2005-10-29 devnull */
175 5cdb1798 2005-10-29 devnull static Part*
176 5cdb1798 2005-10-29 devnull part(Part *pp)
177 5cdb1798 2005-10-29 devnull {
178 5cdb1798 2005-10-29 devnull Part *p, *np;
179 5cdb1798 2005-10-29 devnull
180 5cdb1798 2005-10-29 devnull p = mallocz(sizeof *p, 1);
181 5cdb1798 2005-10-29 devnull p->pp = pp;
182 5cdb1798 2005-10-29 devnull readheader(p);
183 5cdb1798 2005-10-29 devnull
184 5cdb1798 2005-10-29 devnull if(p->boundary != nil){
185 5cdb1798 2005-10-29 devnull /* the format of a multipart part is always:
186 5cdb1798 2005-10-29 devnull * header
187 5cdb1798 2005-10-29 devnull * null or ignored body
188 5cdb1798 2005-10-29 devnull * boundary
189 5cdb1798 2005-10-29 devnull * header
190 5cdb1798 2005-10-29 devnull * body
191 5cdb1798 2005-10-29 devnull * boundary
192 5cdb1798 2005-10-29 devnull * ...
193 5cdb1798 2005-10-29 devnull */
194 5cdb1798 2005-10-29 devnull writeheader(p, 1);
195 5cdb1798 2005-10-29 devnull np = passbody(p, 1);
196 5cdb1798 2005-10-29 devnull if(np != p)
197 5cdb1798 2005-10-29 devnull return np;
198 5cdb1798 2005-10-29 devnull for(;;){
199 5cdb1798 2005-10-29 devnull np = part(p);
200 5cdb1798 2005-10-29 devnull if(np != p)
201 5cdb1798 2005-10-29 devnull return np;
202 5cdb1798 2005-10-29 devnull }
203 5cdb1798 2005-10-29 devnull } else {
204 5cdb1798 2005-10-29 devnull /* no boundary */
205 5cdb1798 2005-10-29 devnull /* may still be multipart if this is a forwarded message */
206 5cdb1798 2005-10-29 devnull if(p->type && cistrcmp(s_to_c(p->type), "message/rfc822") == 0){
207 5cdb1798 2005-10-29 devnull /* the format of forwarded message is:
208 5cdb1798 2005-10-29 devnull * header
209 5cdb1798 2005-10-29 devnull * header
210 5cdb1798 2005-10-29 devnull * body
211 5cdb1798 2005-10-29 devnull */
212 5cdb1798 2005-10-29 devnull writeheader(p, 1);
213 5cdb1798 2005-10-29 devnull passnotheader();
214 5cdb1798 2005-10-29 devnull return part(p);
215 5cdb1798 2005-10-29 devnull } else {
216 5cdb1798 2005-10-29 devnull /*
217 5cdb1798 2005-10-29 devnull * This is the meat. This may be an executable.
218 5cdb1798 2005-10-29 devnull * if so, wrap it and change its type
219 5cdb1798 2005-10-29 devnull */
220 5cdb1798 2005-10-29 devnull if(p->badtype || p->badfile){
221 5cdb1798 2005-10-29 devnull if(p->badfile == 2){
222 5cdb1798 2005-10-29 devnull if(savefile != nil)
223 5cdb1798 2005-10-29 devnull save(p, savefile);
224 5cdb1798 2005-10-29 devnull syslog(0, "vf", "vf rejected %s %s", p->type?s_to_c(p->type):"?",
225 5cdb1798 2005-10-29 devnull p->filename?s_to_c(p->filename):"?");
226 5cdb1798 2005-10-29 devnull fprint(2, "The mail contained an executable attachment.\n");
227 5cdb1798 2005-10-29 devnull fprint(2, "We refuse all mail containing such.\n");
228 5cdb1798 2005-10-29 devnull refuse();
229 5cdb1798 2005-10-29 devnull }
230 5cdb1798 2005-10-29 devnull np = problemchild(p);
231 5cdb1798 2005-10-29 devnull if(np != p)
232 5cdb1798 2005-10-29 devnull return np;
233 5cdb1798 2005-10-29 devnull /* if problemchild returns p, it turns out p is okay: fall thru */
234 5cdb1798 2005-10-29 devnull }
235 5cdb1798 2005-10-29 devnull writeheader(p, 1);
236 5cdb1798 2005-10-29 devnull return passbody(p, 1);
237 5cdb1798 2005-10-29 devnull }
238 5cdb1798 2005-10-29 devnull }
239 5cdb1798 2005-10-29 devnull }
240 5cdb1798 2005-10-29 devnull
241 5cdb1798 2005-10-29 devnull /*
242 5cdb1798 2005-10-29 devnull * read and parse a complete header
243 5cdb1798 2005-10-29 devnull */
244 5cdb1798 2005-10-29 devnull static void
245 5cdb1798 2005-10-29 devnull readheader(Part *p)
246 5cdb1798 2005-10-29 devnull {
247 5cdb1798 2005-10-29 devnull Hline *hl, **l;
248 5cdb1798 2005-10-29 devnull Hdef *hd;
249 5cdb1798 2005-10-29 devnull
250 5cdb1798 2005-10-29 devnull l = &p->hl;
251 5cdb1798 2005-10-29 devnull for(;;){
252 5cdb1798 2005-10-29 devnull hl = readhl();
253 5cdb1798 2005-10-29 devnull if(hl == nil)
254 5cdb1798 2005-10-29 devnull break;
255 5cdb1798 2005-10-29 devnull *l = hl;
256 5cdb1798 2005-10-29 devnull l = &hl->next;
257 5cdb1798 2005-10-29 devnull
258 5cdb1798 2005-10-29 devnull for(hd = hdefs; hd->type != nil; hd++){
259 5cdb1798 2005-10-29 devnull if(cistrncmp(s_to_c(hl->s), hd->type, hd->len) == 0){
260 5cdb1798 2005-10-29 devnull (*hd->f)(p, hd, s_to_c(hl->s));
261 5cdb1798 2005-10-29 devnull break;
262 5cdb1798 2005-10-29 devnull }
263 5cdb1798 2005-10-29 devnull }
264 5cdb1798 2005-10-29 devnull }
265 5cdb1798 2005-10-29 devnull }
266 5cdb1798 2005-10-29 devnull
267 5cdb1798 2005-10-29 devnull /*
268 5cdb1798 2005-10-29 devnull * read a possibly multiline header line
269 5cdb1798 2005-10-29 devnull */
270 5cdb1798 2005-10-29 devnull static Hline*
271 5cdb1798 2005-10-29 devnull readhl(void)
272 5cdb1798 2005-10-29 devnull {
273 5cdb1798 2005-10-29 devnull Hline *hl;
274 5cdb1798 2005-10-29 devnull String *s;
275 5cdb1798 2005-10-29 devnull char *p;
276 5cdb1798 2005-10-29 devnull int n;
277 5cdb1798 2005-10-29 devnull
278 5cdb1798 2005-10-29 devnull p = Brdline(&in, '\n');
279 5cdb1798 2005-10-29 devnull if(p == nil)
280 5cdb1798 2005-10-29 devnull return nil;
281 5cdb1798 2005-10-29 devnull n = Blinelen(&in);
282 5cdb1798 2005-10-29 devnull if(memchr(p, ':', n) == nil){
283 5cdb1798 2005-10-29 devnull Bseek(&in, -n, 1);
284 5cdb1798 2005-10-29 devnull return nil;
285 5cdb1798 2005-10-29 devnull }
286 5cdb1798 2005-10-29 devnull s = s_nappend(s_new(), p, n);
287 5cdb1798 2005-10-29 devnull for(;;){
288 5cdb1798 2005-10-29 devnull p = Brdline(&in, '\n');
289 5cdb1798 2005-10-29 devnull if(p == nil)
290 5cdb1798 2005-10-29 devnull break;
291 5cdb1798 2005-10-29 devnull n = Blinelen(&in);
292 5cdb1798 2005-10-29 devnull if(*p != ' ' && *p != '\t'){
293 5cdb1798 2005-10-29 devnull Bseek(&in, -n, 1);
294 5cdb1798 2005-10-29 devnull break;
295 5cdb1798 2005-10-29 devnull }
296 5cdb1798 2005-10-29 devnull s = s_nappend(s, p, n);
297 5cdb1798 2005-10-29 devnull }
298 5cdb1798 2005-10-29 devnull hl = malloc(sizeof *hl);
299 5cdb1798 2005-10-29 devnull hl->s = s;
300 5cdb1798 2005-10-29 devnull hl->next = nil;
301 5cdb1798 2005-10-29 devnull return hl;
302 5cdb1798 2005-10-29 devnull }
303 5cdb1798 2005-10-29 devnull
304 5cdb1798 2005-10-29 devnull /*
305 5cdb1798 2005-10-29 devnull * write out a complete header
306 5cdb1798 2005-10-29 devnull */
307 5cdb1798 2005-10-29 devnull static void
308 5cdb1798 2005-10-29 devnull writeheader(Part *p, int xfree)
309 5cdb1798 2005-10-29 devnull {
310 5cdb1798 2005-10-29 devnull Hline *hl, *next;
311 5cdb1798 2005-10-29 devnull
312 5cdb1798 2005-10-29 devnull for(hl = p->hl; hl != nil; hl = next){
313 5cdb1798 2005-10-29 devnull Bprint(&out, "%s", s_to_c(hl->s));
314 5cdb1798 2005-10-29 devnull if(xfree)
315 5cdb1798 2005-10-29 devnull s_free(hl->s);
316 5cdb1798 2005-10-29 devnull next = hl->next;
317 5cdb1798 2005-10-29 devnull if(xfree)
318 5cdb1798 2005-10-29 devnull free(hl);
319 5cdb1798 2005-10-29 devnull }
320 5cdb1798 2005-10-29 devnull if(xfree)
321 5cdb1798 2005-10-29 devnull p->hl = nil;
322 5cdb1798 2005-10-29 devnull }
323 5cdb1798 2005-10-29 devnull
324 5cdb1798 2005-10-29 devnull /*
325 5cdb1798 2005-10-29 devnull * pass a body through. return if we hit one of our ancestors'
326 5cdb1798 2005-10-29 devnull * boundaries or EOF. if we hit a boundary, return a pointer to
327 5cdb1798 2005-10-29 devnull * that ancestor. if we hit EOF, return nil.
328 5cdb1798 2005-10-29 devnull */
329 5cdb1798 2005-10-29 devnull static Part*
330 5cdb1798 2005-10-29 devnull passbody(Part *p, int dobound)
331 5cdb1798 2005-10-29 devnull {
332 5cdb1798 2005-10-29 devnull Part *pp;
333 5cdb1798 2005-10-29 devnull Biobuf *b;
334 5cdb1798 2005-10-29 devnull char *cp;
335 5cdb1798 2005-10-29 devnull
336 5cdb1798 2005-10-29 devnull for(;;){
337 5cdb1798 2005-10-29 devnull if(p->tmpbuf){
338 5cdb1798 2005-10-29 devnull b = p->tmpbuf;
339 5cdb1798 2005-10-29 devnull cp = Brdline(b, '\n');
340 5cdb1798 2005-10-29 devnull if(cp == nil){
341 5cdb1798 2005-10-29 devnull Bterm(b);
342 5cdb1798 2005-10-29 devnull p->tmpbuf = nil;
343 5cdb1798 2005-10-29 devnull goto Stdin;
344 5cdb1798 2005-10-29 devnull }
345 5cdb1798 2005-10-29 devnull }else{
346 5cdb1798 2005-10-29 devnull Stdin:
347 5cdb1798 2005-10-29 devnull b = &in;
348 5cdb1798 2005-10-29 devnull cp = Brdline(b, '\n');
349 5cdb1798 2005-10-29 devnull }
350 5cdb1798 2005-10-29 devnull if(cp == nil)
351 5cdb1798 2005-10-29 devnull return nil;
352 5cdb1798 2005-10-29 devnull for(pp = p; pp != nil; pp = pp->pp)
353 5cdb1798 2005-10-29 devnull if(pp->boundary != nil
354 5cdb1798 2005-10-29 devnull && strncmp(cp, s_to_c(pp->boundary), pp->blen) == 0){
355 5cdb1798 2005-10-29 devnull if(dobound)
356 5cdb1798 2005-10-29 devnull Bwrite(&out, cp, Blinelen(b));
357 5cdb1798 2005-10-29 devnull else
358 5cdb1798 2005-10-29 devnull Bseek(b, -Blinelen(b), 1);
359 5cdb1798 2005-10-29 devnull return pp;
360 5cdb1798 2005-10-29 devnull }
361 5cdb1798 2005-10-29 devnull Bwrite(&out, cp, Blinelen(b));
362 5cdb1798 2005-10-29 devnull }
363 5cdb1798 2005-10-29 devnull return nil;
364 5cdb1798 2005-10-29 devnull }
365 5cdb1798 2005-10-29 devnull
366 5cdb1798 2005-10-29 devnull /*
367 5cdb1798 2005-10-29 devnull * save the message somewhere
368 5cdb1798 2005-10-29 devnull */
369 5cdb1798 2005-10-29 devnull static vlong bodyoff; /* clumsy hack */
370 5cdb1798 2005-10-29 devnull static int
371 5cdb1798 2005-10-29 devnull save(Part *p, char *file)
372 5cdb1798 2005-10-29 devnull {
373 5cdb1798 2005-10-29 devnull int fd;
374 5cdb1798 2005-10-29 devnull char *cp;
375 5cdb1798 2005-10-29 devnull
376 5cdb1798 2005-10-29 devnull Bterm(&out);
377 5cdb1798 2005-10-29 devnull memset(&out, 0, sizeof(out));
378 5cdb1798 2005-10-29 devnull
379 5cdb1798 2005-10-29 devnull fd = open(file, OWRITE);
380 5cdb1798 2005-10-29 devnull if(fd < 0)
381 5cdb1798 2005-10-29 devnull return -1;
382 5cdb1798 2005-10-29 devnull seek(fd, 0, 2);
383 5cdb1798 2005-10-29 devnull Binit(&out, fd, OWRITE);
384 5cdb1798 2005-10-29 devnull cp = ctime(time(0));
385 5cdb1798 2005-10-29 devnull cp[28] = 0;
386 5cdb1798 2005-10-29 devnull Bprint(&out, "From virusfilter %s\n", cp);
387 5cdb1798 2005-10-29 devnull writeheader(p, 0);
388 5cdb1798 2005-10-29 devnull bodyoff = Boffset(&out);
389 5cdb1798 2005-10-29 devnull passbody(p, 1);
390 5cdb1798 2005-10-29 devnull Bprint(&out, "\n");
391 5cdb1798 2005-10-29 devnull Bterm(&out);
392 5cdb1798 2005-10-29 devnull close(fd);
393 5cdb1798 2005-10-29 devnull
394 5cdb1798 2005-10-29 devnull memset(&out, 0, sizeof out);
395 5cdb1798 2005-10-29 devnull Binit(&out, 1, OWRITE);
396 5cdb1798 2005-10-29 devnull return 0;
397 5cdb1798 2005-10-29 devnull }
398 5cdb1798 2005-10-29 devnull
399 5cdb1798 2005-10-29 devnull /*
400 5cdb1798 2005-10-29 devnull * write to a file but save the fd for passbody.
401 5cdb1798 2005-10-29 devnull */
402 5cdb1798 2005-10-29 devnull static char*
403 5cdb1798 2005-10-29 devnull savetmp(Part *p)
404 5cdb1798 2005-10-29 devnull {
405 5cdb1798 2005-10-29 devnull char buf[40], *name;
406 5cdb1798 2005-10-29 devnull int fd;
407 5cdb1798 2005-10-29 devnull
408 20bd3ca2 2006-04-09 devnull strcpy(buf, "/var/tmp/vf.XXXXXXXXXXX");
409 20bd3ca2 2006-04-09 devnull if((fd = mkstemp(buf)) < 0){
410 5cdb1798 2005-10-29 devnull fprint(2, "error creating temporary file: %r\n");
411 5cdb1798 2005-10-29 devnull refuse();
412 5cdb1798 2005-10-29 devnull }
413 20bd3ca2 2006-04-09 devnull name = buf;
414 5cdb1798 2005-10-29 devnull close(fd);
415 5cdb1798 2005-10-29 devnull if(save(p, name) < 0){
416 5cdb1798 2005-10-29 devnull fprint(2, "error saving temporary file: %r\n");
417 5cdb1798 2005-10-29 devnull refuse();
418 5cdb1798 2005-10-29 devnull }
419 5cdb1798 2005-10-29 devnull if(p->tmpbuf){
420 5cdb1798 2005-10-29 devnull fprint(2, "error in savetmp: already have tmp file!\n");
421 5cdb1798 2005-10-29 devnull refuse();
422 5cdb1798 2005-10-29 devnull }
423 5cdb1798 2005-10-29 devnull p->tmpbuf = Bopen(name, OREAD|ORCLOSE);
424 5cdb1798 2005-10-29 devnull if(p->tmpbuf == nil){
425 5cdb1798 2005-10-29 devnull fprint(2, "error reading tempoary file: %r\n");
426 5cdb1798 2005-10-29 devnull refuse();
427 5cdb1798 2005-10-29 devnull }
428 5cdb1798 2005-10-29 devnull Bseek(p->tmpbuf, bodyoff, 0);
429 5cdb1798 2005-10-29 devnull return strdup(name);
430 5cdb1798 2005-10-29 devnull }
431 5cdb1798 2005-10-29 devnull
432 5cdb1798 2005-10-29 devnull /*
433 b5f65921 2006-02-11 devnull * Run the external checker to do content-based checks.
434 5cdb1798 2005-10-29 devnull */
435 5cdb1798 2005-10-29 devnull static int
436 5cdb1798 2005-10-29 devnull runchecker(Part *p)
437 5cdb1798 2005-10-29 devnull {
438 5cdb1798 2005-10-29 devnull int pid;
439 5cdb1798 2005-10-29 devnull char *name;
440 5cdb1798 2005-10-29 devnull Waitmsg *w;
441 20bd3ca2 2006-04-09 devnull static char *val;
442 5cdb1798 2005-10-29 devnull
443 20bd3ca2 2006-04-09 devnull if(val == nil)
444 20bd3ca2 2006-04-09 devnull val = unsharp("#9/mail/lib/validateattachment");
445 20bd3ca2 2006-04-09 devnull if(val == nil || access(val, AEXEC) < 0)
446 20bd3ca2 2006-04-09 devnull return 0;
447 20bd3ca2 2006-04-09 devnull
448 5cdb1798 2005-10-29 devnull name = savetmp(p);
449 5cdb1798 2005-10-29 devnull fprint(2, "run checker %s\n", name);
450 5cdb1798 2005-10-29 devnull switch(pid = fork()){
451 5cdb1798 2005-10-29 devnull case -1:
452 5cdb1798 2005-10-29 devnull sysfatal("fork: %r");
453 5cdb1798 2005-10-29 devnull case 0:
454 5cdb1798 2005-10-29 devnull dup(2, 1);
455 20bd3ca2 2006-04-09 devnull execl(val, "validateattachment", name, nil);
456 5cdb1798 2005-10-29 devnull _exits("exec failed");
457 5cdb1798 2005-10-29 devnull }
458 5cdb1798 2005-10-29 devnull
459 5cdb1798 2005-10-29 devnull /*
460 5cdb1798 2005-10-29 devnull * Okay to return on error - will let mail through but wrapped.
461 5cdb1798 2005-10-29 devnull */
462 5cdb1798 2005-10-29 devnull w = wait();
463 827018c4 2006-07-23 devnull remove(name);
464 5cdb1798 2005-10-29 devnull if(w == nil){
465 5cdb1798 2005-10-29 devnull syslog(0, "mail", "vf wait failed: %r");
466 5cdb1798 2005-10-29 devnull return 0;
467 5cdb1798 2005-10-29 devnull }
468 5cdb1798 2005-10-29 devnull if(w->pid != pid){
469 5cdb1798 2005-10-29 devnull syslog(0, "mail", "vf wrong pid %d != %d", w->pid, pid);
470 5cdb1798 2005-10-29 devnull return 0;
471 5cdb1798 2005-10-29 devnull }
472 5cdb1798 2005-10-29 devnull if(p->filename)
473 5cdb1798 2005-10-29 devnull name = s_to_c(p->filename);
474 20bd3ca2 2006-04-09 devnull if(atoi(w->msg) == Discard){
475 5cdb1798 2005-10-29 devnull syslog(0, "mail", "vf validateattachment rejected %s", name);
476 5cdb1798 2005-10-29 devnull refuse();
477 5cdb1798 2005-10-29 devnull }
478 20bd3ca2 2006-04-09 devnull if(atoi(w->msg) == Accept){
479 5cdb1798 2005-10-29 devnull syslog(0, "mail", "vf validateattachment accepted %s", name);
480 5cdb1798 2005-10-29 devnull return 1;
481 5cdb1798 2005-10-29 devnull }
482 5cdb1798 2005-10-29 devnull free(w);
483 5cdb1798 2005-10-29 devnull return 0;
484 5cdb1798 2005-10-29 devnull }
485 5cdb1798 2005-10-29 devnull
486 5cdb1798 2005-10-29 devnull /*
487 5cdb1798 2005-10-29 devnull * emit a multipart Part that explains the problem
488 5cdb1798 2005-10-29 devnull */
489 5cdb1798 2005-10-29 devnull static Part*
490 5cdb1798 2005-10-29 devnull problemchild(Part *p)
491 5cdb1798 2005-10-29 devnull {
492 5cdb1798 2005-10-29 devnull Part *np;
493 5cdb1798 2005-10-29 devnull Hline *hl;
494 5cdb1798 2005-10-29 devnull String *boundary;
495 5cdb1798 2005-10-29 devnull char *cp;
496 5cdb1798 2005-10-29 devnull
497 5cdb1798 2005-10-29 devnull /*
498 5cdb1798 2005-10-29 devnull * We don't know whether the attachment is okay.
499 5cdb1798 2005-10-29 devnull * If there's an external checker, let it have a crack at it.
500 5cdb1798 2005-10-29 devnull */
501 5cdb1798 2005-10-29 devnull if(runchecker(p) > 0)
502 5cdb1798 2005-10-29 devnull return p;
503 5cdb1798 2005-10-29 devnull
504 b5f65921 2006-02-11 devnull if(justreject)
505 b5f65921 2006-02-11 devnull return p;
506 b5f65921 2006-02-11 devnull
507 5cdb1798 2005-10-29 devnull syslog(0, "mail", "vf wrapped %s %s", p->type?s_to_c(p->type):"?",
508 5cdb1798 2005-10-29 devnull p->filename?s_to_c(p->filename):"?");
509 5cdb1798 2005-10-29 devnull
510 5cdb1798 2005-10-29 devnull boundary = mkboundary();
511 5cdb1798 2005-10-29 devnull /* print out non-mime headers */
512 5cdb1798 2005-10-29 devnull for(hl = p->hl; hl != nil; hl = hl->next)
513 5cdb1798 2005-10-29 devnull if(cistrncmp(s_to_c(hl->s), "content-", 8) != 0)
514 5cdb1798 2005-10-29 devnull Bprint(&out, "%s", s_to_c(hl->s));
515 5cdb1798 2005-10-29 devnull
516 5cdb1798 2005-10-29 devnull /* add in our own multipart headers and message */
517 5cdb1798 2005-10-29 devnull Bprint(&out, "Content-Type: multipart/mixed;\n");
518 5cdb1798 2005-10-29 devnull Bprint(&out, "\tboundary=\"%s\"\n", s_to_c(boundary));
519 5cdb1798 2005-10-29 devnull Bprint(&out, "Content-Disposition: inline\n");
520 5cdb1798 2005-10-29 devnull Bprint(&out, "\n");
521 5cdb1798 2005-10-29 devnull Bprint(&out, "This is a multi-part message in MIME format.\n");
522 5cdb1798 2005-10-29 devnull Bprint(&out, "--%s\n", s_to_c(boundary));
523 5cdb1798 2005-10-29 devnull Bprint(&out, "Content-Disposition: inline\n");
524 5cdb1798 2005-10-29 devnull Bprint(&out, "Content-Type: text/plain; charset=\"US-ASCII\"\n");
525 5cdb1798 2005-10-29 devnull Bprint(&out, "Content-Transfer-Encoding: 7bit\n");
526 5cdb1798 2005-10-29 devnull Bprint(&out, "\n");
527 5cdb1798 2005-10-29 devnull Bprint(&out, "from postmaster@%s:\n", sysname());
528 5cdb1798 2005-10-29 devnull Bprint(&out, "The following attachment had content that we can't\n");
529 5cdb1798 2005-10-29 devnull Bprint(&out, "prove to be harmless. To avoid possible automatic\n");
530 5cdb1798 2005-10-29 devnull Bprint(&out, "execution, we changed the content headers.\n");
531 5cdb1798 2005-10-29 devnull Bprint(&out, "The original header was:\n\n");
532 5cdb1798 2005-10-29 devnull
533 5cdb1798 2005-10-29 devnull /* print out original header lines */
534 5cdb1798 2005-10-29 devnull for(hl = p->hl; hl != nil; hl = hl->next)
535 5cdb1798 2005-10-29 devnull if(cistrncmp(s_to_c(hl->s), "content-", 8) == 0)
536 5cdb1798 2005-10-29 devnull Bprint(&out, "\t%s", s_to_c(hl->s));
537 5cdb1798 2005-10-29 devnull Bprint(&out, "--%s\n", s_to_c(boundary));
538 5cdb1798 2005-10-29 devnull
539 5cdb1798 2005-10-29 devnull /* change file name */
540 5cdb1798 2005-10-29 devnull if(p->filename)
541 5cdb1798 2005-10-29 devnull s_append(p->filename, ".suspect");
542 5cdb1798 2005-10-29 devnull else
543 5cdb1798 2005-10-29 devnull p->filename = s_copy("file.suspect");
544 5cdb1798 2005-10-29 devnull
545 5cdb1798 2005-10-29 devnull /* print out new header */
546 5cdb1798 2005-10-29 devnull Bprint(&out, "Content-Type: application/octet-stream\n");
547 5cdb1798 2005-10-29 devnull Bprint(&out, "Content-Disposition: attachment; filename=\"%s\"\n", s_to_c(p->filename));
548 5cdb1798 2005-10-29 devnull switch(p->encoding){
549 5cdb1798 2005-10-29 devnull case Enone:
550 5cdb1798 2005-10-29 devnull break;
551 5cdb1798 2005-10-29 devnull case Ebase64:
552 5cdb1798 2005-10-29 devnull Bprint(&out, "Content-Transfer-Encoding: base64\n");
553 5cdb1798 2005-10-29 devnull break;
554 5cdb1798 2005-10-29 devnull case Equoted:
555 5cdb1798 2005-10-29 devnull Bprint(&out, "Content-Transfer-Encoding: quoted-printable\n");
556 5cdb1798 2005-10-29 devnull break;
557 5cdb1798 2005-10-29 devnull }
558 5cdb1798 2005-10-29 devnull
559 5cdb1798 2005-10-29 devnull /* pass the body */
560 5cdb1798 2005-10-29 devnull np = passbody(p, 0);
561 5cdb1798 2005-10-29 devnull
562 5cdb1798 2005-10-29 devnull /* add the new boundary and the original terminator */
563 5cdb1798 2005-10-29 devnull Bprint(&out, "--%s--\n", s_to_c(boundary));
564 5cdb1798 2005-10-29 devnull if(np && np->boundary){
565 5cdb1798 2005-10-29 devnull cp = Brdline(&in, '\n');
566 5cdb1798 2005-10-29 devnull Bwrite(&out, cp, Blinelen(&in));
567 5cdb1798 2005-10-29 devnull }
568 5cdb1798 2005-10-29 devnull
569 5cdb1798 2005-10-29 devnull return np;
570 5cdb1798 2005-10-29 devnull }
571 5cdb1798 2005-10-29 devnull
572 5cdb1798 2005-10-29 devnull static int
573 5cdb1798 2005-10-29 devnull isattribute(char **pp, char *attr)
574 5cdb1798 2005-10-29 devnull {
575 5cdb1798 2005-10-29 devnull char *p;
576 5cdb1798 2005-10-29 devnull int n;
577 5cdb1798 2005-10-29 devnull
578 5cdb1798 2005-10-29 devnull n = strlen(attr);
579 5cdb1798 2005-10-29 devnull p = *pp;
580 5cdb1798 2005-10-29 devnull if(cistrncmp(p, attr, n) != 0)
581 5cdb1798 2005-10-29 devnull return 0;
582 5cdb1798 2005-10-29 devnull p += n;
583 5cdb1798 2005-10-29 devnull while(*p == ' ')
584 5cdb1798 2005-10-29 devnull p++;
585 5cdb1798 2005-10-29 devnull if(*p++ != '=')
586 5cdb1798 2005-10-29 devnull return 0;
587 5cdb1798 2005-10-29 devnull while(*p == ' ')
588 5cdb1798 2005-10-29 devnull p++;
589 5cdb1798 2005-10-29 devnull *pp = p;
590 5cdb1798 2005-10-29 devnull return 1;
591 5cdb1798 2005-10-29 devnull }
592 5cdb1798 2005-10-29 devnull
593 5cdb1798 2005-10-29 devnull /*
594 5cdb1798 2005-10-29 devnull * parse content type header
595 5cdb1798 2005-10-29 devnull */
596 5cdb1798 2005-10-29 devnull static void
597 5cdb1798 2005-10-29 devnull ctype(Part *p, Hdef *h, char *cp)
598 5cdb1798 2005-10-29 devnull {
599 5cdb1798 2005-10-29 devnull String *s;
600 5cdb1798 2005-10-29 devnull
601 5cdb1798 2005-10-29 devnull cp += h->len;
602 5cdb1798 2005-10-29 devnull cp = skipwhite(cp);
603 5cdb1798 2005-10-29 devnull
604 5cdb1798 2005-10-29 devnull p->type = s_new();
605 5cdb1798 2005-10-29 devnull cp = getstring(cp, p->type, 1);
606 5cdb1798 2005-10-29 devnull if(badtype(s_to_c(p->type)))
607 5cdb1798 2005-10-29 devnull p->badtype = 1;
608 5cdb1798 2005-10-29 devnull
609 5cdb1798 2005-10-29 devnull while(*cp){
610 5cdb1798 2005-10-29 devnull if(isattribute(&cp, "boundary")){
611 5cdb1798 2005-10-29 devnull s = s_new();
612 5cdb1798 2005-10-29 devnull cp = getstring(cp, s, 0);
613 5cdb1798 2005-10-29 devnull p->boundary = s_reset(p->boundary);
614 5cdb1798 2005-10-29 devnull s_append(p->boundary, "--");
615 5cdb1798 2005-10-29 devnull s_append(p->boundary, s_to_c(s));
616 5cdb1798 2005-10-29 devnull p->blen = s_len(p->boundary);
617 5cdb1798 2005-10-29 devnull s_free(s);
618 5cdb1798 2005-10-29 devnull } else if(cistrncmp(cp, "multipart", 9) == 0){
619 5cdb1798 2005-10-29 devnull /*
620 5cdb1798 2005-10-29 devnull * the first unbounded part of a multipart message,
621 5cdb1798 2005-10-29 devnull * the preamble, is not displayed or saved
622 5cdb1798 2005-10-29 devnull */
623 5cdb1798 2005-10-29 devnull } else if(isattribute(&cp, "name")){
624 5cdb1798 2005-10-29 devnull setfilename(p, cp);
625 5cdb1798 2005-10-29 devnull } else if(isattribute(&cp, "charset")){
626 5cdb1798 2005-10-29 devnull if(p->charset == nil)
627 5cdb1798 2005-10-29 devnull p->charset = s_new();
628 5cdb1798 2005-10-29 devnull cp = getstring(cp, s_reset(p->charset), 0);
629 5cdb1798 2005-10-29 devnull }
630 5cdb1798 2005-10-29 devnull
631 5cdb1798 2005-10-29 devnull cp = skiptosemi(cp);
632 5cdb1798 2005-10-29 devnull }
633 5cdb1798 2005-10-29 devnull }
634 5cdb1798 2005-10-29 devnull
635 5cdb1798 2005-10-29 devnull /*
636 5cdb1798 2005-10-29 devnull * parse content encoding header
637 5cdb1798 2005-10-29 devnull */
638 5cdb1798 2005-10-29 devnull static void
639 5cdb1798 2005-10-29 devnull cencoding(Part *m, Hdef *h, char *p)
640 5cdb1798 2005-10-29 devnull {
641 5cdb1798 2005-10-29 devnull p += h->len;
642 5cdb1798 2005-10-29 devnull p = skipwhite(p);
643 5cdb1798 2005-10-29 devnull if(cistrncmp(p, "base64", 6) == 0)
644 5cdb1798 2005-10-29 devnull m->encoding = Ebase64;
645 5cdb1798 2005-10-29 devnull else if(cistrncmp(p, "quoted-printable", 16) == 0)
646 5cdb1798 2005-10-29 devnull m->encoding = Equoted;
647 5cdb1798 2005-10-29 devnull }
648 5cdb1798 2005-10-29 devnull
649 5cdb1798 2005-10-29 devnull /*
650 5cdb1798 2005-10-29 devnull * parse content disposition header
651 5cdb1798 2005-10-29 devnull */
652 5cdb1798 2005-10-29 devnull static void
653 5cdb1798 2005-10-29 devnull cdisposition(Part *p, Hdef *h, char *cp)
654 5cdb1798 2005-10-29 devnull {
655 5cdb1798 2005-10-29 devnull cp += h->len;
656 5cdb1798 2005-10-29 devnull cp = skipwhite(cp);
657 5cdb1798 2005-10-29 devnull while(*cp){
658 5cdb1798 2005-10-29 devnull if(cistrncmp(cp, "inline", 6) == 0){
659 5cdb1798 2005-10-29 devnull p->disposition = Dinline;
660 5cdb1798 2005-10-29 devnull } else if(cistrncmp(cp, "attachment", 10) == 0){
661 5cdb1798 2005-10-29 devnull p->disposition = Dfile;
662 5cdb1798 2005-10-29 devnull } else if(cistrncmp(cp, "filename=", 9) == 0){
663 5cdb1798 2005-10-29 devnull cp += 9;
664 5cdb1798 2005-10-29 devnull setfilename(p, cp);
665 5cdb1798 2005-10-29 devnull }
666 5cdb1798 2005-10-29 devnull cp = skiptosemi(cp);
667 5cdb1798 2005-10-29 devnull }
668 5cdb1798 2005-10-29 devnull
669 5cdb1798 2005-10-29 devnull }
670 5cdb1798 2005-10-29 devnull
671 5cdb1798 2005-10-29 devnull static void
672 5cdb1798 2005-10-29 devnull setfilename(Part *p, char *name)
673 5cdb1798 2005-10-29 devnull {
674 5cdb1798 2005-10-29 devnull if(p->filename == nil)
675 5cdb1798 2005-10-29 devnull p->filename = s_new();
676 5cdb1798 2005-10-29 devnull getstring(name, s_reset(p->filename), 0);
677 5cdb1798 2005-10-29 devnull p->filename = tokenconvert(p->filename);
678 5cdb1798 2005-10-29 devnull p->badfile = badfile(s_to_c(p->filename));
679 5cdb1798 2005-10-29 devnull }
680 5cdb1798 2005-10-29 devnull
681 5cdb1798 2005-10-29 devnull static char*
682 5cdb1798 2005-10-29 devnull skipwhite(char *p)
683 5cdb1798 2005-10-29 devnull {
684 5cdb1798 2005-10-29 devnull while(isspace(*p))
685 5cdb1798 2005-10-29 devnull p++;
686 5cdb1798 2005-10-29 devnull return p;
687 5cdb1798 2005-10-29 devnull }
688 5cdb1798 2005-10-29 devnull
689 5cdb1798 2005-10-29 devnull static char*
690 5cdb1798 2005-10-29 devnull skiptosemi(char *p)
691 5cdb1798 2005-10-29 devnull {
692 5cdb1798 2005-10-29 devnull while(*p && *p != ';')
693 5cdb1798 2005-10-29 devnull p++;
694 5cdb1798 2005-10-29 devnull while(*p == ';' || isspace(*p))
695 5cdb1798 2005-10-29 devnull p++;
696 5cdb1798 2005-10-29 devnull return p;
697 5cdb1798 2005-10-29 devnull }
698 5cdb1798 2005-10-29 devnull
699 5cdb1798 2005-10-29 devnull /*
700 5cdb1798 2005-10-29 devnull * parse a possibly "'d string from a header. A
701 5cdb1798 2005-10-29 devnull * ';' terminates the string.
702 5cdb1798 2005-10-29 devnull */
703 5cdb1798 2005-10-29 devnull static char*
704 5cdb1798 2005-10-29 devnull getstring(char *p, String *s, int dolower)
705 5cdb1798 2005-10-29 devnull {
706 5cdb1798 2005-10-29 devnull s = s_reset(s);
707 5cdb1798 2005-10-29 devnull p = skipwhite(p);
708 5cdb1798 2005-10-29 devnull if(*p == '"'){
709 5cdb1798 2005-10-29 devnull p++;
710 5cdb1798 2005-10-29 devnull for(;*p && *p != '"'; p++)
711 5cdb1798 2005-10-29 devnull if(dolower)
712 5cdb1798 2005-10-29 devnull s_putc(s, tolower(*p));
713 5cdb1798 2005-10-29 devnull else
714 5cdb1798 2005-10-29 devnull s_putc(s, *p);
715 5cdb1798 2005-10-29 devnull if(*p == '"')
716 5cdb1798 2005-10-29 devnull p++;
717 5cdb1798 2005-10-29 devnull s_terminate(s);
718 5cdb1798 2005-10-29 devnull
719 5cdb1798 2005-10-29 devnull return p;
720 5cdb1798 2005-10-29 devnull }
721 5cdb1798 2005-10-29 devnull
722 5cdb1798 2005-10-29 devnull for(; *p && !isspace(*p) && *p != ';'; p++)
723 5cdb1798 2005-10-29 devnull if(dolower)
724 5cdb1798 2005-10-29 devnull s_putc(s, tolower(*p));
725 5cdb1798 2005-10-29 devnull else
726 5cdb1798 2005-10-29 devnull s_putc(s, *p);
727 5cdb1798 2005-10-29 devnull s_terminate(s);
728 5cdb1798 2005-10-29 devnull
729 5cdb1798 2005-10-29 devnull return p;
730 5cdb1798 2005-10-29 devnull }
731 5cdb1798 2005-10-29 devnull
732 5cdb1798 2005-10-29 devnull static void
733 5cdb1798 2005-10-29 devnull init_hdefs(void)
734 5cdb1798 2005-10-29 devnull {
735 5cdb1798 2005-10-29 devnull Hdef *hd;
736 5cdb1798 2005-10-29 devnull static int already;
737 5cdb1798 2005-10-29 devnull
738 5cdb1798 2005-10-29 devnull if(already)
739 5cdb1798 2005-10-29 devnull return;
740 5cdb1798 2005-10-29 devnull already = 1;
741 5cdb1798 2005-10-29 devnull
742 5cdb1798 2005-10-29 devnull for(hd = hdefs; hd->type != nil; hd++)
743 5cdb1798 2005-10-29 devnull hd->len = strlen(hd->type);
744 5cdb1798 2005-10-29 devnull }
745 5cdb1798 2005-10-29 devnull
746 5cdb1798 2005-10-29 devnull /*
747 5cdb1798 2005-10-29 devnull * create a new boundary
748 5cdb1798 2005-10-29 devnull */
749 5cdb1798 2005-10-29 devnull static String*
750 5cdb1798 2005-10-29 devnull mkboundary(void)
751 5cdb1798 2005-10-29 devnull {
752 5cdb1798 2005-10-29 devnull char buf[32];
753 5cdb1798 2005-10-29 devnull int i;
754 5cdb1798 2005-10-29 devnull static int already;
755 5cdb1798 2005-10-29 devnull
756 5cdb1798 2005-10-29 devnull if(already == 0){
757 5cdb1798 2005-10-29 devnull srand((time(0)<<16)|getpid());
758 5cdb1798 2005-10-29 devnull already = 1;
759 5cdb1798 2005-10-29 devnull }
760 5cdb1798 2005-10-29 devnull strcpy(buf, "upas-");
761 5cdb1798 2005-10-29 devnull for(i = 5; i < sizeof(buf)-1; i++)
762 5cdb1798 2005-10-29 devnull buf[i] = 'a' + nrand(26);
763 5cdb1798 2005-10-29 devnull buf[i] = 0;
764 5cdb1798 2005-10-29 devnull return s_copy(buf);
765 5cdb1798 2005-10-29 devnull }
766 5cdb1798 2005-10-29 devnull
767 5cdb1798 2005-10-29 devnull /*
768 5cdb1798 2005-10-29 devnull * skip blank lines till header
769 5cdb1798 2005-10-29 devnull */
770 5cdb1798 2005-10-29 devnull static void
771 5cdb1798 2005-10-29 devnull passnotheader(void)
772 5cdb1798 2005-10-29 devnull {
773 5cdb1798 2005-10-29 devnull char *cp;
774 5cdb1798 2005-10-29 devnull int i, n;
775 5cdb1798 2005-10-29 devnull
776 5cdb1798 2005-10-29 devnull while((cp = Brdline(&in, '\n')) != nil){
777 5cdb1798 2005-10-29 devnull n = Blinelen(&in);
778 5cdb1798 2005-10-29 devnull for(i = 0; i < n-1; i++)
779 5cdb1798 2005-10-29 devnull if(cp[i] != ' ' && cp[i] != '\t' && cp[i] != '\r'){
780 5cdb1798 2005-10-29 devnull Bseek(&in, -n, 1);
781 5cdb1798 2005-10-29 devnull return;
782 5cdb1798 2005-10-29 devnull }
783 5cdb1798 2005-10-29 devnull Bwrite(&out, cp, n);
784 5cdb1798 2005-10-29 devnull }
785 5cdb1798 2005-10-29 devnull }
786 5cdb1798 2005-10-29 devnull
787 5cdb1798 2005-10-29 devnull /*
788 5cdb1798 2005-10-29 devnull * pass unix header lines
789 5cdb1798 2005-10-29 devnull */
790 5cdb1798 2005-10-29 devnull static void
791 5cdb1798 2005-10-29 devnull passunixheader(void)
792 5cdb1798 2005-10-29 devnull {
793 5cdb1798 2005-10-29 devnull char *p;
794 5cdb1798 2005-10-29 devnull int n;
795 5cdb1798 2005-10-29 devnull
796 5cdb1798 2005-10-29 devnull while((p = Brdline(&in, '\n')) != nil){
797 5cdb1798 2005-10-29 devnull n = Blinelen(&in);
798 5cdb1798 2005-10-29 devnull if(strncmp(p, "From ", 5) != 0){
799 5cdb1798 2005-10-29 devnull Bseek(&in, -n, 1);
800 5cdb1798 2005-10-29 devnull break;
801 5cdb1798 2005-10-29 devnull }
802 5cdb1798 2005-10-29 devnull Bwrite(&out, p, n);
803 5cdb1798 2005-10-29 devnull }
804 5cdb1798 2005-10-29 devnull }
805 5cdb1798 2005-10-29 devnull
806 5cdb1798 2005-10-29 devnull /*
807 5cdb1798 2005-10-29 devnull * Read mime types
808 5cdb1798 2005-10-29 devnull */
809 5cdb1798 2005-10-29 devnull static void
810 5cdb1798 2005-10-29 devnull readmtypes(void)
811 5cdb1798 2005-10-29 devnull {
812 5cdb1798 2005-10-29 devnull Biobuf *b;
813 5cdb1798 2005-10-29 devnull char *p;
814 5cdb1798 2005-10-29 devnull char *f[6];
815 5cdb1798 2005-10-29 devnull Mtype *m;
816 5cdb1798 2005-10-29 devnull Mtype **l;
817 5cdb1798 2005-10-29 devnull
818 7ce2007c 2006-02-12 devnull b = Bopen(unsharp("#9/lib/mimetype"), OREAD);
819 5cdb1798 2005-10-29 devnull if(b == nil)
820 5cdb1798 2005-10-29 devnull return;
821 5cdb1798 2005-10-29 devnull
822 5cdb1798 2005-10-29 devnull l = &mtypes;
823 5cdb1798 2005-10-29 devnull while((p = Brdline(b, '\n')) != nil){
824 5cdb1798 2005-10-29 devnull if(*p == '#')
825 5cdb1798 2005-10-29 devnull continue;
826 5cdb1798 2005-10-29 devnull p[Blinelen(b)-1] = 0;
827 5cdb1798 2005-10-29 devnull if(tokenize(p, f, nelem(f)) < 5)
828 5cdb1798 2005-10-29 devnull continue;
829 5cdb1798 2005-10-29 devnull m = mallocz(sizeof *m, 1);
830 5cdb1798 2005-10-29 devnull if(m == nil)
831 5cdb1798 2005-10-29 devnull goto err;
832 5cdb1798 2005-10-29 devnull m->ext = strdup(f[0]);
833 5cdb1798 2005-10-29 devnull if(m->ext == 0)
834 5cdb1798 2005-10-29 devnull goto err;
835 5cdb1798 2005-10-29 devnull m->gtype = strdup(f[1]);
836 5cdb1798 2005-10-29 devnull if(m->gtype == 0)
837 5cdb1798 2005-10-29 devnull goto err;
838 5cdb1798 2005-10-29 devnull m->stype = strdup(f[2]);
839 5cdb1798 2005-10-29 devnull if(m->stype == 0)
840 5cdb1798 2005-10-29 devnull goto err;
841 5cdb1798 2005-10-29 devnull m->class = *f[4];
842 5cdb1798 2005-10-29 devnull *l = m;
843 5cdb1798 2005-10-29 devnull l = &(m->next);
844 5cdb1798 2005-10-29 devnull }
845 5cdb1798 2005-10-29 devnull Bterm(b);
846 5cdb1798 2005-10-29 devnull return;
847 5cdb1798 2005-10-29 devnull err:
848 5cdb1798 2005-10-29 devnull if(m == nil)
849 5cdb1798 2005-10-29 devnull return;
850 5cdb1798 2005-10-29 devnull free(m->ext);
851 5cdb1798 2005-10-29 devnull free(m->gtype);
852 5cdb1798 2005-10-29 devnull free(m->stype);
853 5cdb1798 2005-10-29 devnull free(m);
854 5cdb1798 2005-10-29 devnull Bterm(b);
855 5cdb1798 2005-10-29 devnull }
856 5cdb1798 2005-10-29 devnull
857 5cdb1798 2005-10-29 devnull /*
858 5cdb1798 2005-10-29 devnull * if the class is 'm' or 'y', accept it
859 5cdb1798 2005-10-29 devnull * if the class is 'p' check a previous extension
860 5cdb1798 2005-10-29 devnull * otherwise, filename is bad
861 5cdb1798 2005-10-29 devnull */
862 5cdb1798 2005-10-29 devnull static int
863 5cdb1798 2005-10-29 devnull badfile(char *name)
864 5cdb1798 2005-10-29 devnull {
865 5cdb1798 2005-10-29 devnull char *p;
866 5cdb1798 2005-10-29 devnull Mtype *m;
867 5cdb1798 2005-10-29 devnull int rv;
868 5cdb1798 2005-10-29 devnull
869 5cdb1798 2005-10-29 devnull p = strrchr(name, '.');
870 5cdb1798 2005-10-29 devnull if(p == nil)
871 5cdb1798 2005-10-29 devnull return 0;
872 5cdb1798 2005-10-29 devnull
873 5cdb1798 2005-10-29 devnull for(m = mtypes; m != nil; m = m->next)
874 5cdb1798 2005-10-29 devnull if(cistrcmp(p, m->ext) == 0){
875 5cdb1798 2005-10-29 devnull switch(m->class){
876 5cdb1798 2005-10-29 devnull case 'm':
877 5cdb1798 2005-10-29 devnull case 'y':
878 5cdb1798 2005-10-29 devnull return 0;
879 5cdb1798 2005-10-29 devnull case 'p':
880 5cdb1798 2005-10-29 devnull *p = 0;
881 5cdb1798 2005-10-29 devnull rv = badfile(name);
882 5cdb1798 2005-10-29 devnull *p = '.';
883 5cdb1798 2005-10-29 devnull return rv;
884 5cdb1798 2005-10-29 devnull case 'r':
885 5cdb1798 2005-10-29 devnull return 2;
886 5cdb1798 2005-10-29 devnull }
887 5cdb1798 2005-10-29 devnull }
888 5cdb1798 2005-10-29 devnull return 1;
889 5cdb1798 2005-10-29 devnull }
890 5cdb1798 2005-10-29 devnull
891 5cdb1798 2005-10-29 devnull /*
892 5cdb1798 2005-10-29 devnull * if the class is 'm' or 'y' or 'p', accept it
893 5cdb1798 2005-10-29 devnull * otherwise, filename is bad
894 5cdb1798 2005-10-29 devnull */
895 5cdb1798 2005-10-29 devnull static int
896 5cdb1798 2005-10-29 devnull badtype(char *type)
897 5cdb1798 2005-10-29 devnull {
898 5cdb1798 2005-10-29 devnull Mtype *m;
899 5cdb1798 2005-10-29 devnull char *s, *fix;
900 5cdb1798 2005-10-29 devnull int rv = 1;
901 5cdb1798 2005-10-29 devnull
902 5cdb1798 2005-10-29 devnull fix = s = strchr(type, '/');
903 5cdb1798 2005-10-29 devnull if(s != nil)
904 5cdb1798 2005-10-29 devnull *s++ = 0;
905 5cdb1798 2005-10-29 devnull else
906 5cdb1798 2005-10-29 devnull s = "-";
907 5cdb1798 2005-10-29 devnull
908 5cdb1798 2005-10-29 devnull for(m = mtypes; m != nil; m = m->next){
909 5cdb1798 2005-10-29 devnull if(cistrcmp(type, m->gtype) != 0)
910 5cdb1798 2005-10-29 devnull continue;
911 5cdb1798 2005-10-29 devnull if(cistrcmp(s, m->stype) != 0)
912 5cdb1798 2005-10-29 devnull continue;
913 5cdb1798 2005-10-29 devnull switch(m->class){
914 5cdb1798 2005-10-29 devnull case 'y':
915 5cdb1798 2005-10-29 devnull case 'p':
916 5cdb1798 2005-10-29 devnull case 'm':
917 5cdb1798 2005-10-29 devnull rv = 0;
918 5cdb1798 2005-10-29 devnull break;
919 5cdb1798 2005-10-29 devnull }
920 5cdb1798 2005-10-29 devnull break;
921 5cdb1798 2005-10-29 devnull }
922 5cdb1798 2005-10-29 devnull
923 5cdb1798 2005-10-29 devnull if(fix != nil)
924 5cdb1798 2005-10-29 devnull *fix = '/';
925 5cdb1798 2005-10-29 devnull return rv;
926 5cdb1798 2005-10-29 devnull }
927 5cdb1798 2005-10-29 devnull
928 5cdb1798 2005-10-29 devnull /* rfc2047 non-ascii */
929 5cdb1798 2005-10-29 devnull typedef struct Charset Charset;
930 5cdb1798 2005-10-29 devnull struct Charset {
931 5cdb1798 2005-10-29 devnull char *name;
932 5cdb1798 2005-10-29 devnull int len;
933 5cdb1798 2005-10-29 devnull int convert;
934 5cdb1798 2005-10-29 devnull } charsets[] =
935 5cdb1798 2005-10-29 devnull {
936 5cdb1798 2005-10-29 devnull { "us-ascii", 8, 1, },
937 5cdb1798 2005-10-29 devnull { "utf-8", 5, 0, },
938 cbeb0b26 2006-04-01 devnull { "iso-8859-1", 10, 1, }
939 5cdb1798 2005-10-29 devnull };
940 5cdb1798 2005-10-29 devnull
941 5cdb1798 2005-10-29 devnull /*
942 5cdb1798 2005-10-29 devnull * convert to UTF if need be
943 5cdb1798 2005-10-29 devnull */
944 5cdb1798 2005-10-29 devnull static String*
945 5cdb1798 2005-10-29 devnull tokenconvert(String *t)
946 5cdb1798 2005-10-29 devnull {
947 5cdb1798 2005-10-29 devnull String *s;
948 5cdb1798 2005-10-29 devnull char decoded[1024];
949 5cdb1798 2005-10-29 devnull char utfbuf[2*1024];
950 5cdb1798 2005-10-29 devnull int i, len;
951 5cdb1798 2005-10-29 devnull char *e;
952 5cdb1798 2005-10-29 devnull char *token;
953 5cdb1798 2005-10-29 devnull
954 5cdb1798 2005-10-29 devnull token = s_to_c(t);
955 5cdb1798 2005-10-29 devnull len = s_len(t);
956 5cdb1798 2005-10-29 devnull
957 5cdb1798 2005-10-29 devnull if(token[0] != '=' || token[1] != '?' ||
958 5cdb1798 2005-10-29 devnull token[len-2] != '?' || token[len-1] != '=')
959 5cdb1798 2005-10-29 devnull goto err;
960 5cdb1798 2005-10-29 devnull e = token+len-2;
961 5cdb1798 2005-10-29 devnull token += 2;
962 5cdb1798 2005-10-29 devnull
963 cbeb0b26 2006-04-01 devnull /* bail if we don't understand the character set */
964 5cdb1798 2005-10-29 devnull for(i = 0; i < nelem(charsets); i++)
965 5cdb1798 2005-10-29 devnull if(cistrncmp(charsets[i].name, token, charsets[i].len) == 0)
966 5cdb1798 2005-10-29 devnull if(token[charsets[i].len] == '?'){
967 5cdb1798 2005-10-29 devnull token += charsets[i].len + 1;
968 5cdb1798 2005-10-29 devnull break;
969 5cdb1798 2005-10-29 devnull }
970 5cdb1798 2005-10-29 devnull if(i >= nelem(charsets))
971 5cdb1798 2005-10-29 devnull goto err;
972 5cdb1798 2005-10-29 devnull
973 cbeb0b26 2006-04-01 devnull /* bail if it doesn't fit */
974 5cdb1798 2005-10-29 devnull if(strlen(token) > sizeof(decoded)-1)
975 5cdb1798 2005-10-29 devnull goto err;
976 5cdb1798 2005-10-29 devnull
977 cbeb0b26 2006-04-01 devnull /* bail if we don't understand the encoding */
978 5cdb1798 2005-10-29 devnull if(cistrncmp(token, "b?", 2) == 0){
979 5cdb1798 2005-10-29 devnull token += 2;
980 5cdb1798 2005-10-29 devnull len = dec64((uchar*)decoded, sizeof(decoded), token, e-token);
981 5cdb1798 2005-10-29 devnull decoded[len] = 0;
982 5cdb1798 2005-10-29 devnull } else if(cistrncmp(token, "q?", 2) == 0){
983 5cdb1798 2005-10-29 devnull token += 2;
984 5cdb1798 2005-10-29 devnull len = decquoted(decoded, token, e);
985 5cdb1798 2005-10-29 devnull if(len > 0 && decoded[len-1] == '\n')
986 5cdb1798 2005-10-29 devnull len--;
987 5cdb1798 2005-10-29 devnull decoded[len] = 0;
988 5cdb1798 2005-10-29 devnull } else
989 5cdb1798 2005-10-29 devnull goto err;
990 5cdb1798 2005-10-29 devnull
991 5cdb1798 2005-10-29 devnull s = nil;
992 5cdb1798 2005-10-29 devnull switch(charsets[i].convert){
993 5cdb1798 2005-10-29 devnull case 0:
994 5cdb1798 2005-10-29 devnull s = s_copy(decoded);
995 5cdb1798 2005-10-29 devnull break;
996 5cdb1798 2005-10-29 devnull case 1:
997 5cdb1798 2005-10-29 devnull s = s_new();
998 5cdb1798 2005-10-29 devnull latin1toutf(utfbuf, decoded, decoded+len);
999 5cdb1798 2005-10-29 devnull s_append(s, utfbuf);
1000 5cdb1798 2005-10-29 devnull break;
1001 5cdb1798 2005-10-29 devnull }
1002 5cdb1798 2005-10-29 devnull
1003 5cdb1798 2005-10-29 devnull return s;
1004 5cdb1798 2005-10-29 devnull err:
1005 5cdb1798 2005-10-29 devnull return s_clone(t);
1006 5cdb1798 2005-10-29 devnull }
1007 5cdb1798 2005-10-29 devnull
1008 5cdb1798 2005-10-29 devnull /*
1009 5cdb1798 2005-10-29 devnull * decode quoted
1010 5cdb1798 2005-10-29 devnull */
1011 5cdb1798 2005-10-29 devnull enum
1012 5cdb1798 2005-10-29 devnull {
1013 5cdb1798 2005-10-29 devnull Self= 1,
1014 cbeb0b26 2006-04-01 devnull Hex= 2
1015 5cdb1798 2005-10-29 devnull };
1016 5cdb1798 2005-10-29 devnull uchar tableqp[256];
1017 5cdb1798 2005-10-29 devnull
1018 5cdb1798 2005-10-29 devnull static void
1019 5cdb1798 2005-10-29 devnull initquoted(void)
1020 5cdb1798 2005-10-29 devnull {
1021 5cdb1798 2005-10-29 devnull int c;
1022 5cdb1798 2005-10-29 devnull
1023 5cdb1798 2005-10-29 devnull memset(tableqp, 0, 256);
1024 5cdb1798 2005-10-29 devnull for(c = ' '; c <= '<'; c++)
1025 5cdb1798 2005-10-29 devnull tableqp[c] = Self;
1026 5cdb1798 2005-10-29 devnull for(c = '>'; c <= '~'; c++)
1027 5cdb1798 2005-10-29 devnull tableqp[c] = Self;
1028 5cdb1798 2005-10-29 devnull tableqp['\t'] = Self;
1029 5cdb1798 2005-10-29 devnull tableqp['='] = Hex;
1030 5cdb1798 2005-10-29 devnull }
1031 5cdb1798 2005-10-29 devnull
1032 5cdb1798 2005-10-29 devnull static int
1033 5cdb1798 2005-10-29 devnull hex2int(int x)
1034 5cdb1798 2005-10-29 devnull {
1035 5cdb1798 2005-10-29 devnull if(x >= '0' && x <= '9')
1036 5cdb1798 2005-10-29 devnull return x - '0';
1037 5cdb1798 2005-10-29 devnull if(x >= 'A' && x <= 'F')
1038 5cdb1798 2005-10-29 devnull return (x - 'A') + 10;
1039 5cdb1798 2005-10-29 devnull if(x >= 'a' && x <= 'f')
1040 5cdb1798 2005-10-29 devnull return (x - 'a') + 10;
1041 5cdb1798 2005-10-29 devnull return 0;
1042 5cdb1798 2005-10-29 devnull }
1043 5cdb1798 2005-10-29 devnull
1044 5cdb1798 2005-10-29 devnull static char*
1045 5cdb1798 2005-10-29 devnull decquotedline(char *out, char *in, char *e)
1046 5cdb1798 2005-10-29 devnull {
1047 5cdb1798 2005-10-29 devnull int c, soft;
1048 5cdb1798 2005-10-29 devnull
1049 5cdb1798 2005-10-29 devnull /* dump trailing white space */
1050 5cdb1798 2005-10-29 devnull while(e >= in && (*e == ' ' || *e == '\t' || *e == '\r' || *e == '\n'))
1051 5cdb1798 2005-10-29 devnull e--;
1052 5cdb1798 2005-10-29 devnull
1053 5cdb1798 2005-10-29 devnull /* trailing '=' means no newline */
1054 5cdb1798 2005-10-29 devnull if(*e == '='){
1055 5cdb1798 2005-10-29 devnull soft = 1;
1056 5cdb1798 2005-10-29 devnull e--;
1057 5cdb1798 2005-10-29 devnull } else
1058 5cdb1798 2005-10-29 devnull soft = 0;
1059 5cdb1798 2005-10-29 devnull
1060 5cdb1798 2005-10-29 devnull while(in <= e){
1061 5cdb1798 2005-10-29 devnull c = (*in++) & 0xff;
1062 5cdb1798 2005-10-29 devnull switch(tableqp[c]){
1063 5cdb1798 2005-10-29 devnull case Self:
1064 5cdb1798 2005-10-29 devnull *out++ = c;
1065 5cdb1798 2005-10-29 devnull break;
1066 5cdb1798 2005-10-29 devnull case Hex:
1067 5cdb1798 2005-10-29 devnull c = hex2int(*in++)<<4;
1068 5cdb1798 2005-10-29 devnull c |= hex2int(*in++);
1069 5cdb1798 2005-10-29 devnull *out++ = c;
1070 5cdb1798 2005-10-29 devnull break;
1071 5cdb1798 2005-10-29 devnull }
1072 5cdb1798 2005-10-29 devnull }
1073 5cdb1798 2005-10-29 devnull if(!soft)
1074 5cdb1798 2005-10-29 devnull *out++ = '\n';
1075 5cdb1798 2005-10-29 devnull *out = 0;
1076 5cdb1798 2005-10-29 devnull
1077 5cdb1798 2005-10-29 devnull return out;
1078 5cdb1798 2005-10-29 devnull }
1079 5cdb1798 2005-10-29 devnull
1080 5cdb1798 2005-10-29 devnull static int
1081 5cdb1798 2005-10-29 devnull decquoted(char *out, char *in, char *e)
1082 5cdb1798 2005-10-29 devnull {
1083 5cdb1798 2005-10-29 devnull char *p, *nl;
1084 5cdb1798 2005-10-29 devnull
1085 5cdb1798 2005-10-29 devnull if(tableqp[' '] == 0)
1086 5cdb1798 2005-10-29 devnull initquoted();
1087 5cdb1798 2005-10-29 devnull
1088 5cdb1798 2005-10-29 devnull p = out;
1089 5cdb1798 2005-10-29 devnull while((nl = strchr(in, '\n')) != nil && nl < e){
1090 5cdb1798 2005-10-29 devnull p = decquotedline(p, in, nl);
1091 5cdb1798 2005-10-29 devnull in = nl + 1;
1092 5cdb1798 2005-10-29 devnull }
1093 5cdb1798 2005-10-29 devnull if(in < e)
1094 5cdb1798 2005-10-29 devnull p = decquotedline(p, in, e-1);
1095 5cdb1798 2005-10-29 devnull
1096 cbeb0b26 2006-04-01 devnull /* make sure we end with a new line */
1097 5cdb1798 2005-10-29 devnull if(*(p-1) != '\n'){
1098 5cdb1798 2005-10-29 devnull *p++ = '\n';
1099 5cdb1798 2005-10-29 devnull *p = 0;
1100 5cdb1798 2005-10-29 devnull }
1101 5cdb1798 2005-10-29 devnull
1102 5cdb1798 2005-10-29 devnull return p - out;
1103 5cdb1798 2005-10-29 devnull }
1104 5cdb1798 2005-10-29 devnull
1105 5cdb1798 2005-10-29 devnull /* translate latin1 directly since it fits neatly in utf */
1106 5cdb1798 2005-10-29 devnull static int
1107 5cdb1798 2005-10-29 devnull latin1toutf(char *out, char *in, char *e)
1108 5cdb1798 2005-10-29 devnull {
1109 5cdb1798 2005-10-29 devnull Rune r;
1110 5cdb1798 2005-10-29 devnull char *p;
1111 5cdb1798 2005-10-29 devnull
1112 5cdb1798 2005-10-29 devnull p = out;
1113 5cdb1798 2005-10-29 devnull for(; in < e; in++){
1114 5cdb1798 2005-10-29 devnull r = (*in) & 0xff;
1115 5cdb1798 2005-10-29 devnull p += runetochar(p, &r);
1116 5cdb1798 2005-10-29 devnull }
1117 5cdb1798 2005-10-29 devnull *p = 0;
1118 5cdb1798 2005-10-29 devnull return p - out;
1119 5cdb1798 2005-10-29 devnull }