drop mem_alloc and mem_free, use my own hand crafted optmized macros that
[apps/madmutt.git] / mutt_idna.c
1 /*
2  * Copyright notice from original mutt:
3  * Copyright (C) 2003 Thomas Roessler <roessler@does-not-exist.org>
4  *
5  * This file is part of mutt-ng, see http://www.muttng.org/.
6  * It's licensed under the GNU General Public License,
7  * please see the file GPL in the top level source directory.
8  */
9
10 #if HAVE_CONFIG_H
11 # include "config.h"
12 #endif
13
14 #include <lib-lib/mem.h>
15
16 #include "mutt.h"
17 #include "ascii.h"
18 #include "charset.h"
19 #include "mutt_idna.h"
20
21 #include "lib/mem.h"
22 #include "lib/intl.h"
23 #include "lib/str.h"
24 #include "lib/debug.h"
25
26 /* The low-level interface we use. */
27
28 #ifndef HAVE_LIBIDN
29
30 int mutt_idna_to_local (const char *in, char **out, int flags)
31 {
32   *out = str_dup (in);
33   return 1;
34 }
35
36 int mutt_local_to_idna (const char *in, char **out)
37 {
38   *out = str_dup (in);
39   return 0;
40 }
41
42 #else
43
44 int mutt_idna_to_local (const char *in, char **out, int flags)
45 {
46   *out = NULL;
47
48   if (!option (OPTUSEIDN))
49     goto notrans;
50
51   if (!in)
52     goto notrans;
53
54   /* Is this the right function?  Interesting effects with some bad identifiers! */
55   if (idna_to_unicode_8z8z (in, out, 1) != IDNA_SUCCESS)
56     goto notrans;
57   if (mutt_convert_string (out, "utf-8", Charset, M_ICONV_HOOK_TO) == -1)
58     goto notrans;
59
60   /* 
61    * make sure that we can convert back and come out with the same
62    * domain name. 
63    */
64
65   if ((flags & MI_MAY_BE_IRREVERSIBLE) == 0) {
66     int irrev = 0;
67     char *t2 = NULL;
68     char *tmp = str_dup (*out);
69
70     if (mutt_convert_string (&tmp, Charset, "utf-8", M_ICONV_HOOK_FROM) == -1)
71       irrev = 1;
72     if (!irrev && idna_to_ascii_8z (tmp, &t2, 1) != IDNA_SUCCESS)
73       irrev = 1;
74     if (!irrev && ascii_strcasecmp (t2, in)) {
75       debug_print (1, ("not reversible. in = '%s', t2 = '%s'.\n", in, t2));
76       irrev = 1;
77     }
78
79     p_delete(&t2);
80     p_delete(&tmp);
81
82     if (irrev)
83       goto notrans;
84   }
85
86   return 0;
87
88 notrans:
89   p_delete(out);
90   *out = str_dup (in);
91   return 1;
92 }
93
94 int mutt_local_to_idna (const char *in, char **out)
95 {
96   int rv = 0;
97   char *tmp = str_dup (in);
98
99   *out = NULL;
100
101   if (!in) {
102     *out = NULL;
103     return -1;
104   }
105
106   if (mutt_convert_string (&tmp, Charset, "utf-8", M_ICONV_HOOK_FROM) == -1)
107     rv = -1;
108   if (!rv && idna_to_ascii_8z (tmp, out, 1) != IDNA_SUCCESS)
109     rv = -2;
110
111   p_delete(&tmp);
112   if (rv < 0) {
113     p_delete(out);
114     *out = str_dup (in);
115   }
116   return rv;
117 }
118
119 #endif
120
121
122 /* higher level functions */
123
124 static int mbox_to_udomain (const char *mbx, char **user, char **domain)
125 {
126   char *p;
127
128   *user = NULL;
129   *domain = NULL;
130
131   p = strchr (mbx, '@');
132   if (!p || !p[1])
133     return -1;
134   *user = mem_calloc ((p - mbx + 1), sizeof (mbx[0]));
135   strfcpy (*user, mbx, (p - mbx + 1));
136   *domain = str_dup (p + 1);
137   return 0;
138 }
139
140 int mutt_addrlist_to_idna (ADDRESS * a, char **err)
141 {
142   char *user = NULL, *domain = NULL;
143   char *tmp = NULL;
144   int e = 0;
145
146   if (err)
147     *err = NULL;
148
149   for (; a; a = a->next) {
150     if (!a->mailbox)
151       continue;
152     if (mbox_to_udomain (a->mailbox, &user, &domain) == -1)
153       continue;
154
155     if (mutt_local_to_idna (domain, &tmp) < 0) {
156       e = 1;
157       if (err)
158         *err = str_dup (domain);
159     }
160     else {
161       mem_realloc (&a->mailbox, str_len (user) + str_len (tmp) + 2);
162       sprintf (a->mailbox, "%s@%s", NONULL (user), NONULL (tmp));       /* __SPRINTF_CHECKED__ */
163     }
164
165     p_delete(&domain);
166     p_delete(&user);
167     p_delete(&tmp);
168
169     if (e)
170       return -1;
171   }
172
173   return 0;
174 }
175
176 int mutt_addrlist_to_local (ADDRESS * a)
177 {
178   char *user, *domain;
179   char *tmp = NULL;
180
181   for (; a; a = a->next) {
182     if (!a->mailbox)
183       continue;
184     if (mbox_to_udomain (a->mailbox, &user, &domain) == -1)
185       continue;
186
187     if (mutt_idna_to_local (domain, &tmp, 0) == 0) {
188       mem_realloc (&a->mailbox, str_len (user) + str_len (tmp) + 2);
189       sprintf (a->mailbox, "%s@%s", NONULL (user), NONULL (tmp));       /* __SPRINTF_CHECKED__ */
190     }
191
192     p_delete(&domain);
193     p_delete(&user);
194     p_delete(&tmp);
195   }
196
197   return 0;
198 }
199
200 /* convert just for displaying purposes */
201 const char *mutt_addr_for_display (ADDRESS * a)
202 {
203   static char *buff = NULL;
204   char *tmp = NULL;
205
206   /* user and domain will be either allocated or reseted to the NULL in
207    * the mbox_to_udomain(), but for safety... */
208   char *domain = NULL;
209   char *user = NULL;
210
211   p_delete(&buff);
212
213   if (mbox_to_udomain (a->mailbox, &user, &domain) != 0)
214     return a->mailbox;
215   if (mutt_idna_to_local (domain, &tmp, MI_MAY_BE_IRREVERSIBLE) != 0) {
216     p_delete(&user);
217     p_delete(&domain);
218     p_delete(&tmp);
219     return a->mailbox;
220   }
221
222   mem_realloc (&buff, str_len (tmp) + str_len (user) + 2);
223   sprintf (buff, "%s@%s", NONULL (user), NONULL (tmp)); /* __SPRINTF_CHECKED__ */
224   p_delete(&tmp);
225   p_delete(&user);
226   p_delete(&domain);
227   return buff;
228 }
229
230 /* Convert an ENVELOPE structure */
231
232 void mutt_env_to_local (ENVELOPE * e)
233 {
234   mutt_addrlist_to_local (e->return_path);
235   mutt_addrlist_to_local (e->from);
236   mutt_addrlist_to_local (e->to);
237   mutt_addrlist_to_local (e->cc);
238   mutt_addrlist_to_local (e->bcc);
239   mutt_addrlist_to_local (e->reply_to);
240   mutt_addrlist_to_local (e->mail_followup_to);
241 }
242
243 /* Note that `a' in the `env->a' expression is macro argument, not
244  * "real" name of an `env' compound member.  Real name will be substituted
245  * by preprocessor at the macro-expansion time.
246  */
247 #define H_TO_IDNA(a)    \
248   if (mutt_addrlist_to_idna (env->a, err) && !e) \
249   { \
250      if (tag) *tag = #a; e = 1; err = NULL; \
251   }
252
253 int mutt_env_to_idna (ENVELOPE * env, const char **tag, const char **err)
254 {
255   int e = 0;
256
257   H_TO_IDNA (return_path);
258   H_TO_IDNA (from);
259   H_TO_IDNA (to);
260   H_TO_IDNA (cc);
261   H_TO_IDNA (bcc);
262   H_TO_IDNA (reply_to);
263   H_TO_IDNA (mail_followup_to);
264   return e;
265 }
266
267 #undef H_TO_IDNA