ze-filter  (ze-filter-0.8.0-develop-180218)
ze-mimelist.c
Go to the documentation of this file.
1 
2 /*
3  *
4  * ze-filter - Mail Server Filter for sendmail
5  *
6  * Copyright (c) 2001-2018 - Jose-Marcio Martins da Cruz
7  *
8  * Auteur : Jose Marcio Martins da Cruz
9  * jose.marcio.mc@gmail.org
10  *
11  * Historique :
12  * Creation : janvier 2002
13  *
14  * This program is free software, but with restricted license :
15  *
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
20  *
21  * More details about ze-filter license can be found at ze-filter
22  * web site : http://foss.jose-marcio.org
23  */
24 
25 #include <ze-sys.h>
26 
27 #include "ze-filter.h"
28 
29 #ifndef TRUE
30 #define TRUE 1
31 #define FALSE 0
32 #endif
33 
34 static bool is_attachment(char *, char *, char *);
35 char *chomp_filename(char *);
36 
37 /* ****************************************************************************
38  * *
39  * *
40  **************************************************************************** */
41 char *
43  char *s;
44 {
45  int n;
46  char *p;
47 
48  if (s == NULL)
49  return s;
50 
51 #if 0
52  {
53  int d;
54 
55  for (d = strlen(s) - 1; d >= 0; d--) {
56  if (strchr(' .\t', s[d]) != NULL)
57  s[d] = '\0';
58  else
59  break;
60  }
61  return s;
62  }
63 #else
64  while ((n = strlen(s)) > 0) {
65  if ((p = strchr(". \t,", s[n - 1])) != NULL) {
66  s[n - 1] = '\0';
67  continue;
68  }
69  break;
70  }
71 #endif
72  return s;
73 }
74 
75 /* ****************************************************************************
76  * *
77  * *
78  **************************************************************************** */
79 bool
80 add_content_field_attr(c, name, value)
81  content_field_T *c;
82  char *name;
83  char *value;
84 {
85  int i;
86 
87  if (c == NULL)
88  return FALSE;
89  if ((name == NULL) || (value == NULL))
90  return FALSE;
91  for (i = 0; i < NB_ATTR; i++) {
92  if ((c->attr[i].name != NULL) || (c->attr[i].value != NULL))
93  continue;
94 
95  if (strlen(name) > 0) {
96  c->attr[i].name = strdup(name);
97  if (c->attr[i].name == NULL)
98  ZE_LogSysError("strdup(name) error");
99  }
100 
101  if (strlen(value) > 0) {
102  c->attr[i].value = strdup(value);
103  if (c->attr[i].value == NULL)
104  ZE_LogSysError("strdup(value) error");
105  }
106  break;
107  }
108  return (i < NB_ATTR);
109 }
110 
111 /* ****************************************************************************
112  * *
113  * *
114  **************************************************************************** */
117  content_field_T *buf;
118  content_field_T **head;
119 {
120  content_field_T *new;
121 
122  if ((buf == NULL) || (head == NULL))
123  return NULL;
124 
125  if ((new = (content_field_T *) malloc(sizeof (content_field_T))) == NULL) {
126  ZE_LogSysError("malloc (content_field)");
127  return NULL;
128  }
129 
130  *new = *buf;
131 
132  if (*head != NULL) {
133  content_field_T *p = *head;
134 
135  while (p->next != NULL)
136  p = p->next;
137  p->next = new;
138  } else
139  *head = new;
140  new->next = NULL;
141 
142  memset(buf, 0, sizeof (content_field_T));
143 
144  return *head;
145 }
146 
147 /* ****************************************************************************
148  * *
149  * *
150  **************************************************************************** */
151 void
153  content_field_T *p;
154 {
155  int i;
156 
157  if (p == NULL)
158  return;
159 
160  if (p->value != NULL)
161  FREE(p->value);
162  for (i = 0; i < NB_ATTR; i++) {
163  if (p->attr[i].name != NULL)
164  FREE(p->attr[i].name);
165  if (p->attr[i].value != NULL)
166  FREE(p->attr[i].value);
167  }
168  FREE(p);
169 }
170 
171 /* ****************************************************************************
172  * *
173  * *
174  **************************************************************************** */
175 void
177  content_field_T *p;
178 {
179  int i;
180 
181  if (p == NULL)
182  return;
183 
184  if (p->value != NULL)
185  FREE(p->value);
186 
187  for (i = 0; i < NB_ATTR; i++) {
188  if (p->attr[i].name != NULL)
189  FREE(p->attr[i].name);
190  if (p->attr[i].value != NULL)
191  FREE(p->attr[i].value);
192  }
193  memset(p, 0, sizeof (content_field_T));
194 }
195 
196 /* ****************************************************************************
197  * *
198  * *
199  **************************************************************************** */
200 void
202  content_field_T *head;
203 {
204  content_field_T *p = head;
205 
206  while (head != NULL) {
207  p = head->next;
208  free_content_field(head);
209  head = p;
210  }
211 }
212 
213 /* ****************************************************************************
214  * *
215  * *
216  **************************************************************************** */
217 void
219  attachment_T *head;
220 {
221  attachment_T *p = head;
222 
223  while (head != NULL) {
224  p = head->next;
225  if (head->name != NULL)
226  FREE(head->name);
227  if (head->disposition != NULL)
228  FREE(head->disposition);
229  if (head->mimetype != NULL)
230  FREE(head->mimetype);
231  FREE(head);
232  head = p;
233  }
234 }
235 
236 
237 /* ****************************************************************************
238  * *
239  * *
240  **************************************************************************** */
241 
242 attachment_T *
243 add_attachment(file, head)
244  attachment_T *file;
245  attachment_T **head;
246 {
247  if (head == NULL)
248  return NULL;
249 
250  if (file == NULL)
251  return *head;
252 
253  if (*head != NULL) {
254  attachment_T *p = *head;
255 
256  while (p->next != NULL)
257  p = p->next;
258  p->next = file;
259  } else
260  *head = file;
261  file->next = NULL;
262 
263  return *head;
264 }
265 
266 /* ****************************************************************************
267  * *
268  * *
269  **************************************************************************** */
270 
271 attachment_T *
272 get_attachment(filename, head)
273  char *filename;
274  attachment_T *head;
275 {
276  attachment_T *p = head;
277 
278  if ((filename == NULL) || (head == NULL))
279  return NULL;
280 
281  while (p != NULL) {
282  if ((p->name != NULL) && (strcasecmp(filename, p->name) == 0))
283  return p;
284  p = p->next;
285  }
286  return NULL;
287 }
288 
289 
290 /* ****************************************************************************
291  * *
292  * *
293  **************************************************************************** */
294 static bool
295 is_attachment(mimetype, attr, value)
296  char *mimetype;
297  char *attr;
298  char *value;
299 {
300  if ((attr == NULL) || (value == NULL))
301  return FALSE;
302 
303  if ((strcasecmp("name", attr) == 0) && (strlen(value) > 0))
304  return TRUE;
305 
306  if ((strcasecmp("filename", attr) == 0) && (strlen(value) > 0))
307  return TRUE;
308 
309  if (mimetype != NULL) {
310  if (strcasecmp("message/partial", mimetype) == 0) {
311  if (strcasecmp("id", attr) == 0)
312  return TRUE;
313  }
314 
315  if (strcasecmp("message/external-body", mimetype) == 0) {
316  if (strcasecmp("name", attr) == 0)
317  return TRUE;
318  }
319  }
320 
321  return FALSE;
322 }
323 
324 
325 /* ****************************************************************************
326  * *
327  * *
328  **************************************************************************** */
329 int
330 extract_attachments(chead, ahead)
331  content_field_T *chead;
332  attachment_T **ahead;
333 {
334  char buf[1024];
335  int nb = 0;
336  int i;
337 
338  content_field_T *p;
339 
340  /*
341  ** Content-Type
342  **
343  */
344  for (p = chead; p != NULL; p = p->next) {
345  if (p->field_type == CT_TYPE) {
346  for (i = 0; i < NB_ATTR; i++) {
347  attachment_T *file;
348  char filename[2048];
349 
350  if (p->attr[i].name == NULL)
351  continue;
352 
353  if (!is_attachment(p->value, p->attr[i].name, p->attr[i].value))
354  continue;
355 
356  file = (attachment_T *) malloc(sizeof (attachment_T));
357  if (file == NULL) {
358  ZE_LogSysError("file = malloc...");
359  continue;
360  }
361  file->name = strdup(p->attr[i].value);
362  if (file->name == NULL) {
363  ZE_LogSysError("file->name = strdup(p->attr[i].value)");
364  FREE(file);
365  continue;
366  }
367  file->mimetype = strdup(p->value);
368  if (file->mimetype == NULL) {
369  ZE_LogSysError("file->mimetype = strdup(p->value)");
370  FREE(file);
371  continue;
372  }
373  get_file_disposition(chead, p->attr[i].value, buf, sizeof (buf));
374  file->disposition = strdup(buf);
375  if (file->disposition == NULL) {
376  ZE_LogSysError("file->disposition = strdup(buf)");
377  FREE(file->name);
378  FREE(file->mimetype);
379  FREE(file);
380  continue;
381  }
382 
383  if (is_rfc1521_encoded(p->attr[i].value))
384  decode_rfc1521(filename, p->attr[i].value, sizeof (filename));
385  else
386  strlcpy(filename, p->attr[i].value, sizeof (filename));
387 
388  /*
389  * Look if filename ends with a "."
390  */
391  chomp_filename(filename);
392 
393 #if _FFR_FILENAME_7BIT
395 #endif
396 
397  file->xfile = check_filename_xfile(filename);
398 
399 #undef _FFR_RFC2046_MSGS_ARE_XFILES
400  /*
401  * RFC 2046
402  */
403 #if _FFR_RFC2046_MSGS_ARE_XFILES == 1
404  if ((file->mimetype != NULL) &&
405  ((strcasecmp(file->mimetype, "message/partial") == 0) ||
406  (strcasecmp(file->mimetype, "message/external-body") == 0)))
407  file->xfile = 1;
408 #endif
409  add_attachment(file, ahead);
410  nb++;
411  }
412  }
413  }
414 
415  /*
416  ** Content-Disposition
417  **
418  */
419 
420  /*
421  * Now, it's time too look at Content-Disposition tags
422  */
423  for (p = chead; p != NULL; p = p->next) {
424  if (p->field_type == CT_DISP) {
425  for (i = 0; i < NB_ATTR; i++) {
426  attachment_T *file;
427  char filename[2048];
428 
429  if (p->attr[i].name == NULL)
430  continue;
431 
432  if (!is_attachment(p->value, p->attr[i].name, p->attr[i].value))
433  continue;
434 
435  if ((file = get_attachment(p->attr[i].value, *ahead)) != NULL)
436  continue;
437 
438  file = (attachment_T *) malloc(sizeof (attachment_T));
439  if (file == NULL) {
440  ZE_LogSysError("file = malloc...");
441  continue;
442  }
443  file->name = strdup(p->attr[i].value);
444  if (file->name == NULL) {
445  ZE_LogSysError("file->name = strdup(p->attr[i].value)");
446  FREE(file);
447  continue;
448  }
449  file->disposition = strdup(p->value);
450  if (file->disposition == NULL) {
451  ZE_LogSysError("file->disposition = strdup(p->disposition)");
452  FREE(file->name);
453  FREE(file);
454  continue;
455  }
456  file->mimetype = NULL;
457 
458  if (is_rfc1521_encoded(p->attr[i].value))
459  decode_rfc1521(filename, p->attr[i].value, sizeof (filename));
460  else
461  strlcpy(filename, p->attr[i].value, sizeof (filename));
462 
463  /*
464  * Look if filename ends with a "."
465  */
466  chomp_filename(filename);
467 
468 #if _FFR_FILENAME_7BIT
470 #endif
471 
472  file->xfile = check_filename_xfile(filename);
473 
474  add_attachment(file, ahead);
475  nb++;
476  }
477  }
478  }
479 
480  /*
481  ** UUencoded files
482  **
483  */
484  /*
485  * Last but not least, uuencoded files
486  */
487  for (p = chead; p != NULL; p = p->next) {
488  if (p->field_type == CT_UUFILE) {
489  attachment_T *file;
490 
491  if (p->value == NULL || strlen(p->value) == 0) {
492  continue;
493  }
494 
495  file = (attachment_T *) malloc(sizeof (attachment_T));
496  if (file == NULL) {
497  ZE_LogSysError("file = malloc...");
498  continue;
499  }
500  file->name = strdup(p->value);
501  if (file->name == NULL) {
502  ZE_LogSysError("file->name = strdup(p->value)");
503  FREE(file);
504  continue;
505  }
506 
507  file->mimetype = NULL;
508  file->disposition = strdup("uuencoded");
509  if (file->disposition == NULL) {
510  ZE_LogSysError("file->disposition = strdup(uuencoded)");
511  FREE(file->name);
512  FREE(file);
513  continue;
514  }
515 
516  /*
517  * Look if filename ends with a "."
518  */
519  chomp_filename(file->name);
520 
521 #if _FFR_FILENAME_7BIT
523 #endif
524 
525  file->xfile = check_filename_xfile(file->name);
526  add_attachment(file, ahead);
527 
528  nb++;
529  }
530  }
531 
532  return nb;
533 }
534 
535 /* ****************************************************************************
536  * *
537  * *
538  **************************************************************************** */
539 int
541  content_field_T *chead;
542  attachment_T **ahead;
543 {
544  char buf[1024];
545  int nb = 0;
546  int i;
547 
548  content_field_T *p;
549 
550  /*
551  * Let's take a look at Content-Type tags
552  */
553  for (p = chead; p != NULL; p = p->next) {
554  if (p->field_type == CT_UUFILE) {
555 
556  continue;
557  }
558 
559  for (i = 0; i < NB_ATTR; i++) {
560  attachment_T *file;
561  char filename[2048];
562 
563  if ((p->attr[i].name == NULL) || (strlen(p->attr[i].name) == 0))
564  continue;
565 
566  if (!is_attachment(p->value, p->attr[i].name, p->attr[i].value))
567  continue;
568 
569  if (is_rfc1521_encoded(p->attr[i].value))
570  decode_rfc1521(filename, p->attr[i].value, sizeof (filename));
571  else
572  strlcpy(filename, p->attr[i].value, sizeof (filename));
573 
574  /*
575  * Look if filename ends with a "."
576  */
577  chomp_filename(filename);
578 
579  if ((file = get_attachment(filename, *ahead)) != NULL) {
580  switch (p->field_type) {
581  case CT_TYPE:
582  if (file->disposition == NULL) {
583 
584  }
585  break;
586  case CT_DISP:
587  if (file->mimetype == NULL) {
588 
589  }
590  break;
591  default:
592  break;
593  }
594  continue;
595  }
596 
597  file = (attachment_T *) malloc(sizeof (attachment_T));
598  if (file == NULL) {
599  ZE_LogSysError("file = malloc...");
600  continue;
601  }
602  memset(file, 0, sizeof (*file));
603  file->name = strdup(filename);
604  if (file->name == NULL) {
605  ZE_LogSysError("file->name = strdup(filename)");
606  FREE(file);
607  continue;
608  }
609 
610  file->mimetype = strdup(p->value);
611  if (file->mimetype == NULL) {
612  ZE_LogSysError("file->mimetype = strdup(p->value)");
613  FREE(file);
614  continue;
615  }
616  get_file_disposition(chead, p->attr[i].value, buf, sizeof (buf));
617  file->disposition = strdup(buf);
618  if (file->disposition == NULL) {
619  ZE_LogSysError("file->disposition = strdup(buf)");
620  FREE(file->name);
621  FREE(file->mimetype);
622  FREE(file);
623  continue;
624  }
625 
626  file->xfile = check_filename_xfile(filename);
627 
628  add_attachment(file, ahead);
629  nb++;
630  }
631  }
632 
633  /*
634  * Last but not least, uuencoded files
635  */
636  for (p = chead; p != NULL; p = p->next) {
637  attachment_T *file;
638 
639  if (p->field_type != CT_UUFILE)
640  continue;
641 
642  file = (attachment_T *) malloc(sizeof (attachment_T));
643  if (file == NULL) {
644  ZE_LogSysError("file = malloc...");
645  continue;
646  }
647  file->name = strdup(p->value);
648  if (file->name == NULL) {
649  ZE_LogSysError("file->name = strdup(p->value)");
650  FREE(file);
651  continue;
652  }
653 
654  file->mimetype = NULL;
655  file->disposition = strdup("uuencoded");
656  if (file->disposition == NULL) {
657  ZE_LogSysError("file->disposition = strdup(uuencoded)");
658  FREE(file->name);
659  FREE(file);
660  continue;
661  }
662 
663  /*
664  * Look if filename ends with a "."
665  */
666  chomp_filename(file->name);
667 
668  file->xfile = check_filename_xfile(file->name);
669 
670  add_attachment(file, ahead);
671  nb++;
672  }
673 
674  return nb;
675 }
676 
677 
678 /* ****************************************************************************
679  * *
680  * *
681  **************************************************************************** */
682 int
683 get_file_disposition(head, name, value, sz)
684  content_field_T *head;
685  char *name;
686  char *value;
687  size_t sz;
688 {
689  content_field_T *p = head;
690  int i;
691 
692  *value = '\0';
693  if (head == NULL)
694  return 0;
695  while (p != NULL) {
696  if (p->field_type != CT_DISP) {
697  p = p->next;
698  continue;
699  }
700  if (p->value == NULL) {
701  p = p->next;
702  continue;
703  }
704  for (i = 0; i < NB_ATTR; i++) {
705  if ((p->attr[i].name != NULL) &&
706  (strcasecmp(p->attr[i].name, "filename") == 0) &&
707  (p->attr[i].value != NULL)
708  && (strcasecmp(p->attr[i].value, name) == 0)) {
709  strlcpy(value, STRNULL(p->value, ""), sz);
710  return 1;
711  }
712  }
713  p = p->next;
714  }
715  return 0;
716 }
char * chomp_filename(char *)
Definition: ze-mimelist.c:42
void free_attachment_list(attachment_T *head)
Definition: ze-mimelist.c:218
attachment_T * add_attachment(attachment_T *file, attachment_T **head)
Definition: ze-mimelist.c:243
#define CT_TYPE
Definition: ze-scanmail.h:32
void free_content_field_rec(content_field_T *p)
Definition: ze-mimelist.c:176
#define FREE(x)
Definition: macros.h:37
#define STRNULL(x, r)
Definition: macros.h:81
bool check_filename_xfile(char *)
Definition: ze-fileexp.c:342
#define strlcpy
Definition: zeString.h:32
content_field_T * next
Definition: ze-mimelist.h:57
#define FALSE
Definition: ze-mimelist.c:31
#define strchr
Definition: ze-sys.h:218
int get_file_disposition(content_field_T *head, char *name, char *value, size_t sz)
Definition: ze-mimelist.c:683
int extract_attachments(content_field_T *chead, attachment_T **ahead)
Definition: ze-mimelist.c:330
int nb
Definition: ze-connopen.c:61
void free_content_field(content_field_T *p)
Definition: ze-mimelist.c:152
#define NB_ATTR
Definition: ze-mimelist.h:48
content_field_T * save_content_field(content_field_T *buf, content_field_T **head)
Definition: ze-mimelist.c:116
content_text_T attr[NB_ATTR]
Definition: ze-mimelist.h:56
#define ZE_LogSysError(...)
Definition: zeSyslog.h:129
int new_extract_attachments(content_field_T *chead, attachment_T **ahead)
Definition: ze-mimelist.c:540
char * mimetype
Definition: ze-mimelist.h:72
#define TRUE
Definition: ze-mimelist.c:30
int decode_rfc1521(char *, char *, size_t)
Definition: ze-decode.c:75
#define CT_UUFILE
Definition: ze-scanmail.h:34
void free_content_field_list(content_field_T *head)
Definition: ze-mimelist.c:201
bool is_rfc1521_encoded(char *)
Definition: ze-decode.c:62
void convert_filename_8to7(char *buf)
char * name
Definition: ze-mimelist.h:70
bool add_content_field_attr(content_field_T *c, char *name, char *value)
Definition: ze-mimelist.c:80
#define CT_DISP
Definition: ze-scanmail.h:33
struct attachment_T * next
Definition: ze-mimelist.h:74
attachment_T * get_attachment(char *filename, attachment_T *head)
Definition: ze-mimelist.c:272
char * disposition
Definition: ze-mimelist.h:71