common: Prepare for parsing mail sub-addresses.
[gnupg.git] / common / t-mbox-util.c
1 /* t-mbox-util.c - Module test for mbox-util.c
2  * Copyright (C) 2015 Werner Koch
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <https://www.gnu.org/licenses/>.
18  */
19
20 #include <config.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24
25 #include "util.h"
26 #include "mbox-util.h"
27
28 #define PGM "t-mbox-util"
29
30
31 #define pass()  do { ; } while(0)
32 #define fail(a)  do { fprintf (stderr, "%s:%d: test %d failed\n",\
33                                __FILE__,__LINE__, (a));          \
34                        exit (1);                                 \
35                     } while(0)
36
37
38 static int verbose;
39 static int debug;
40
41
42 static void
43 run_mbox_test (void)
44 {
45   static struct
46   {
47     const char *userid;
48     const char *mbox;
49   } testtbl[] =
50     {
51       { "Werner Koch <wk@gnupg.org>", "wk@gnupg.org" },
52       { "<wk@gnupg.org>", "wk@gnupg.org" },
53       { "wk@gnupg.org", "wk@gnupg.org" },
54       { "wk@gnupg.org ", NULL },
55       { " wk@gnupg.org", NULL },
56       { "Werner Koch (test) <wk@gnupg.org>", "wk@gnupg.org" },
57       { "Werner Koch <wk@gnupg.org> (test)", "wk@gnupg.org" },
58       { "Werner Koch <wk@gnupg.org (test)", NULL },
59       { "Werner Koch <wk@gnupg.org >", NULL },
60       { "Werner Koch <wk@gnupg.org", NULL },
61       { "", NULL },
62       { "@", NULL },
63       { "bar <>", NULL },
64       { "<foo@example.org>", "foo@example.org" },
65       { "<foo.@example.org>", "foo.@example.org" },
66       { "<.foo.@example.org>", ".foo.@example.org" },
67       { "<foo..@example.org>", "foo..@example.org" },
68       { "<foo..bar@example.org>", "foo..bar@example.org" },
69       { "<foo@example.org.>", NULL },
70       { "<foo@example..org>", NULL },
71       { "<foo@.>", NULL },
72       { "<@example.org>", NULL },
73       { "<foo@@example.org>", NULL },
74       { "<@foo@example.org>", NULL },
75       { "<foo@example.org> ()", "foo@example.org" },
76       { "<fo()o@example.org> ()", "fo()o@example.org" },
77       { "<fo()o@example.org> ()", "fo()o@example.org" },
78       { "fo()o@example.org", NULL},
79       { "Mr. Foo <foo@example.org><bar@example.net>", "foo@example.org"},
80       { NULL, NULL }
81     };
82   int idx;
83
84   for (idx=0; testtbl[idx].userid; idx++)
85     {
86       char *mbox = mailbox_from_userid (testtbl[idx].userid, 0);
87
88       if (!testtbl[idx].mbox)
89         {
90           if (mbox)
91             fail (idx);
92         }
93       else if (!mbox)
94         fail (idx);
95       else if (strcmp (mbox, testtbl[idx].mbox))
96         fail (idx);
97
98       xfree (mbox);
99     }
100 }
101
102
103 static void
104 run_mbox_no_sub_test (void)
105 {
106   static struct
107   {
108     const char *userid;
109     const char *mbox;
110   } testtbl[] =
111     {
112       { "foo+bar@example.org", "foo@example.org" },
113       { "Werner Koch <wk@gnupg.org>", "wk@gnupg.org" },
114       { "<wk@gnupg.org>", "wk@gnupg.org" },
115       { "wk@gnupg.org", "wk@gnupg.org" },
116       { "wk@gnupg.org ", NULL },
117       { " wk@gnupg.org", NULL },
118       { "Werner Koch (test) <wk@gnupg.org>", "wk@gnupg.org" },
119       { "Werner Koch <wk@gnupg.org> (test)", "wk@gnupg.org" },
120       { "Werner Koch <wk@gnupg.org (test)", NULL },
121       { "Werner Koch <wk@gnupg.org >", NULL },
122       { "Werner Koch <wk@gnupg.org", NULL },
123       { "", NULL },
124       { "@", NULL },
125       { "bar <>", NULL },
126       { "<foo@example.org>", "foo@example.org" },
127       { "<foo.@example.org>", "foo.@example.org" },
128       { "<.foo.@example.org>", ".foo.@example.org" },
129       { "<foo..@example.org>", "foo..@example.org" },
130       { "<foo..bar@example.org>", "foo..bar@example.org" },
131       { "<foo@example.org.>", NULL },
132       { "<foo@example..org>", NULL },
133       { "<foo@.>", NULL },
134       { "<@example.org>", NULL },
135       { "<foo@@example.org>", NULL },
136       { "<@foo@example.org>", NULL },
137       { "<foo@example.org> ()", "foo@example.org" },
138       { "<fo()o@example.org> ()", "fo()o@example.org" },
139       { "<fo()o@example.org> ()", "fo()o@example.org" },
140       { "fo()o@example.org", NULL},
141       { "Mr. Foo <foo@example.org><bar@example.net>", "foo@example.org"},
142       { "foo+bar@example.org", "foo@example.org" },
143       { "foo++bar@example.org", "foo++bar@example.org" },
144       { "foo++@example.org", "foo++@example.org" },
145       { "foo+@example.org", "foo+@example.org" },
146       { "+foo@example.org", "+foo@example.org" },
147       { "++foo@example.org", "++foo@example.org" },
148       { "+foo+@example.org", "+foo+@example.org" },
149       { "+@example.org", "+@example.org" },
150       { "++@example.org", "++@example.org" },
151       { "foo+b@example.org", "foo@example.org" },
152       { "foo+ba@example.org", "foo@example.org" },
153       { "foo+bar@example.org", "foo@example.org" },
154       { "foo+barb@example.org", "foo@example.org" },
155       { "foo+barba@example.org", "foo@example.org" },
156       { "f+b@example.org", "f@example.org" },
157       { "fo+b@example.org", "fo@example.org" },
158
159       { NULL, NULL }
160     };
161   int idx;
162
163   for (idx=0; testtbl[idx].userid; idx++)
164     {
165       char *mbox = mailbox_from_userid (testtbl[idx].userid, 1);
166
167       if (!testtbl[idx].mbox)
168         {
169           if (mbox)
170             fail (idx);
171         }
172       else if (!mbox)
173         fail (idx);
174       else if (strcmp (mbox, testtbl[idx].mbox))
175         fail (idx);
176
177       xfree (mbox);
178     }
179 }
180
181
182 static void
183 run_dns_test (void)
184 {
185   static struct
186   {
187     const char *name;
188     int valid;
189   } testtbl[] =
190     {
191       { "", 0 },
192       { ".", 0 },
193       { "-", 0 },
194       { "a", 1 },
195       { "ab", 1 },
196       { "a.b", 1 },
197       { "a.b.", 1 },
198       { ".a.b.", 0 },
199       { ".a.b", 0 },
200       { "-a.b", 0 },
201       { "a-.b", 0 },
202       { "a.-b", 0 },
203       { "a.b-", 0 },
204       { "a.b-.", 0 },
205       { "a..b", 0 },
206       { "ab.c", 1 },
207       { "a-b.c", 1 },
208       { "a-b-.c", 0 },
209       { "-a-b.c", 0 },
210       { "example.org", 1 },
211       { "x.example.org", 1 },
212       { "xy.example.org", 1 },
213       { "Xy.example.org", 1 },
214       { "-Xy.example.org", 0 },
215       { "Xy.example-.org", 0 },
216       { "foo.example.org..", 0 },
217       { "foo.example.org.", 1 },
218       { ".foo.example.org.", 0 },
219       { "..foo.example.org.", 0 },
220       { NULL, 0 }
221     };
222   int idx;
223
224   for (idx=0; testtbl[idx].name; idx++)
225     {
226       if (is_valid_domain_name (testtbl[idx].name) != testtbl[idx].valid)
227         fail (idx);
228     }
229 }
230
231
232 static void
233 run_filter (int no_sub)
234 {
235   char buf[4096];
236   int c;
237   char *p, *mbox;
238   unsigned int count1 = 0;
239   unsigned int count2 = 0;
240
241   while (fgets (buf, sizeof buf, stdin))
242     {
243       p = strchr (buf, '\n');
244       if (p)
245         *p = 0;
246       else
247         {
248           /* Skip to the end of the line.  */
249           while ((c = getc (stdin)) != EOF && c != '\n')
250             ;
251         }
252       count1++;
253       trim_spaces (buf);
254       mbox = mailbox_from_userid (buf, no_sub);
255       if (mbox)
256         {
257           printf ("%s\n", mbox);
258           xfree (mbox);
259           count2++;
260         }
261     }
262   if (verbose)
263     fprintf (stderr, PGM ": lines=%u mboxes=%u\n", count1, count2);
264 }
265
266
267 int
268 main (int argc, char **argv)
269 {
270   int last_argc = -1;
271   int opt_filter = 0;
272   int opt_no_sub = 0;
273
274   if (argc)
275     { argc--; argv++; }
276   while (argc && last_argc != argc )
277     {
278       last_argc = argc;
279       if (!strcmp (*argv, "--"))
280         {
281           argc--; argv++;
282           break;
283         }
284       else if (!strcmp (*argv, "--help"))
285         {
286           fputs ("usage: " PGM " [FILE]\n"
287                  "Options:\n"
288                  "  --verbose         Print timings etc.\n"
289                  "  --debug           Flyswatter\n"
290                  "  --filter          Filter mboxes from input lines\n"
291                  "  --no-sub          Ignore '+'-sub-addresses\n"
292                  , stdout);
293           exit (0);
294         }
295       else if (!strcmp (*argv, "--verbose"))
296         {
297           verbose++;
298           argc--; argv++;
299         }
300       else if (!strcmp (*argv, "--debug"))
301         {
302           verbose += 2;
303           debug++;
304           argc--; argv++;
305         }
306       else if (!strcmp (*argv, "--filter"))
307         {
308           opt_filter = 1;
309           argc--; argv++;
310         }
311       else if (!strcmp (*argv, "--no-sub"))
312         {
313           opt_no_sub = 1;
314           argc--; argv++;
315         }
316       else if (!strncmp (*argv, "--", 2))
317         {
318           fprintf (stderr, PGM ": unknown option '%s'\n", *argv);
319           exit (1);
320         }
321     }
322
323   if (opt_filter)
324     run_filter (opt_no_sub);
325   else
326     {
327       run_mbox_test ();
328       run_mbox_no_sub_test ();
329       run_dns_test ();
330     }
331
332   return 0;
333 }