fix segfault
[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 = p_dupstr(mbx, p - mbx);
135   *domain = str_dup (p + 1);
136   return 0;
137 }
138
139 int mutt_addrlist_to_idna (ADDRESS * a, char **err)
140 {
141   char *user = NULL, *domain = NULL;
142   char *tmp = NULL;
143   int e = 0;
144
145   if (err)
146     *err = NULL;
147
148   for (; a; a = a->next) {
149     if (!a->mailbox)
150       continue;
151     if (mbox_to_udomain (a->mailbox, &user, &domain) == -1)
152       continue;
153
154     if (mutt_local_to_idna (domain, &tmp) < 0) {
155       e = 1;
156       if (err)
157         *err = str_dup (domain);
158     }
159     else {
160       mem_realloc (&a->mailbox, str_len (user) + str_len (tmp) + 2);
161       sprintf (a->mailbox, "%s@%s", NONULL (user), NONULL (tmp));       /* __SPRINTF_CHECKED__ */
162     }
163
164     p_delete(&domain);
165     p_delete(&user);
166     p_delete(&tmp);
167
168     if (e)
169       return -1;
170   }
171
172   return 0;
173 }
174
175 int mutt_addrlist_to_local (ADDRESS * a)
176 {
177   char *user, *domain;
178   char *tmp = NULL;
179
180   for (; a; a = a->next) {
181     if (!a->mailbox)
182       continue;
183     if (mbox_to_udomain (a->mailbox, &user, &domain) == -1)
184       continue;
185
186     if (mutt_idna_to_local (domain, &tmp, 0) == 0) {
187       mem_realloc (&a->mailbox, str_len (user) + str_len (tmp) + 2);
188       sprintf (a->mailbox, "%s@%s", NONULL (user), NONULL (tmp));       /* __SPRINTF_CHECKED__ */
189     }
190
191     p_delete(&domain);
192     p_delete(&user);
193     p_delete(&tmp);
194   }
195
196   return 0;
197 }
198
199 /* convert just for displaying purposes */
200 const char *mutt_addr_for_display (ADDRESS * a)
201 {
202   static char *buff = NULL;
203   char *tmp = NULL;
204
205   /* user and domain will be either allocated or reseted to the NULL in
206    * the mbox_to_udomain(), but for safety... */
207   char *domain = NULL;
208   char *user = NULL;
209
210   p_delete(&buff);
211
212   if (mbox_to_udomain (a->mailbox, &user, &domain) != 0)
213     return a->mailbox;
214   if (mutt_idna_to_local (domain, &tmp, MI_MAY_BE_IRREVERSIBLE) != 0) {
215     p_delete(&user);
216     p_delete(&domain);
217     p_delete(&tmp);
218     return a->mailbox;
219   }
220
221   mem_realloc (&buff, str_len (tmp) + str_len (user) + 2);
222   sprintf (buff, "%s@%s", NONULL (user), NONULL (tmp)); /* __SPRINTF_CHECKED__ */
223   p_delete(&tmp);
224   p_delete(&user);
225   p_delete(&domain);
226   return buff;
227 }
228
229 /* Convert an ENVELOPE structure */
230
231 void mutt_env_to_local (ENVELOPE * e)
232 {
233   mutt_addrlist_to_local (e->return_path);
234   mutt_addrlist_to_local (e->from);
235   mutt_addrlist_to_local (e->to);
236   mutt_addrlist_to_local (e->cc);
237   mutt_addrlist_to_local (e->bcc);
238   mutt_addrlist_to_local (e->reply_to);
239   mutt_addrlist_to_local (e->mail_followup_to);
240 }
241
242 /* Note that `a' in the `env->a' expression is macro argument, not
243  * "real" name of an `env' compound member.  Real name will be substituted
244  * by preprocessor at the macro-expansion time.
245  */
246 #define H_TO_IDNA(a)    \
247   if (mutt_addrlist_to_idna (env->a, err) && !e) \
248   { \
249      if (tag) *tag = #a; e = 1; err = NULL; \
250   }
251
252 int mutt_env_to_idna (ENVELOPE * env, const char **tag, const char **err)
253 {
254   int e = 0;
255
256   H_TO_IDNA (return_path);
257   H_TO_IDNA (from);
258   H_TO_IDNA (to);
259   H_TO_IDNA (cc);
260   H_TO_IDNA (bcc);
261   H_TO_IDNA (reply_to);
262   H_TO_IDNA (mail_followup_to);
263   return e;
264 }
265
266 #undef H_TO_IDNA