using stls should not enable new CAPAs
[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 #include <lib-lib/lib-lib.h>
11
12 #ifdef HAVE_LIBIDN
13 #include <idna.h>
14 #endif
15
16 #include "mutt.h"
17 #include "charset.h"
18 #include "mutt_idna.h"
19
20 /* The low-level interface we use. */
21
22 static int mutt_idna_to_local(const char *in, char **out, bool nonreverseok)
23 {
24 #ifdef HAVE_LIBIDN
25   *out = NULL;
26
27   if (!option (OPTUSEIDN))
28     goto notrans;
29
30   if (!in)
31     goto notrans;
32
33   /* Is this the right function?  Interesting effects with some bad identifiers! */
34   if (idna_to_unicode_8z8z (in, out, 1) != IDNA_SUCCESS)
35     goto notrans;
36   if (mutt_convert_string (out, "utf-8", mod_cset.charset, M_ICONV_HOOK_TO) == -1)
37     goto notrans;
38
39   /* 
40    * make sure that we can convert back and come out with the same
41    * domain name. 
42    */
43
44   if (nonreverseok) {
45     int irrev = 0;
46     char *t2 = NULL;
47     char *tmp = m_strdup(*out);
48
49     if (mutt_convert_string (&tmp, mod_cset.charset, "utf-8", M_ICONV_HOOK_FROM) == -1)
50       irrev = 1;
51     if (!irrev && idna_to_ascii_8z (tmp, &t2, 1) != IDNA_SUCCESS)
52       irrev = 1;
53     if (!irrev && ascii_strcasecmp (t2, in)) {
54       irrev = 1;
55     }
56
57     p_delete(&t2);
58     p_delete(&tmp);
59
60     if (irrev)
61       goto notrans;
62   }
63
64   return 0;
65
66 notrans:
67   p_delete(out);
68 #endif
69   *out = m_strdup(in);
70   return 1;
71 }
72
73 static int mutt_local_to_idna (const char *in, char **out)
74 {
75 #ifdef HAVE_LIBIDN
76   int rv = 0;
77   char *tmp = m_strdup(in);
78
79   *out = NULL;
80
81   if (!in) {
82     *out = NULL;
83     return -1;
84   }
85
86   if (mutt_convert_string (&tmp, mod_cset.charset, "utf-8", M_ICONV_HOOK_FROM) == -1)
87     rv = -1;
88   if (!rv && idna_to_ascii_8z (tmp, out, 1) != IDNA_SUCCESS)
89     rv = -2;
90
91   p_delete(&tmp);
92   if (rv < 0) {
93     p_delete(out);
94     *out = m_strdup(in);
95   }
96   return rv;
97 #else
98   *out = m_strdup(in);
99   return 0;
100 #endif
101 }
102
103 /* higher level functions */
104
105 static int mbox_to_udomain (const char *mbx, char **user, char **domain)
106 {
107   char *p;
108
109   *user = NULL;
110   *domain = NULL;
111
112   p = strchr (mbx, '@');
113   if (!p || !p[1])
114     return -1;
115   *user = p_dupstr(mbx, p - mbx);
116   *domain = m_strdup(p + 1);
117   return 0;
118 }
119
120 int mutt_addrlist_to_idna (address_t * a, char **err)
121 {
122   char *user = NULL, *domain = NULL;
123   char *tmp = NULL;
124   int e = 0;
125
126   if (err)
127     *err = NULL;
128
129   for (; a; a = a->next) {
130     if (!a->mailbox)
131       continue;
132     if (mbox_to_udomain (a->mailbox, &user, &domain) == -1)
133       continue;
134
135     if (mutt_local_to_idna (domain, &tmp) < 0) {
136       e = 1;
137       if (err)
138         *err = m_strdup(domain);
139     }
140     else {
141       p_realloc(&a->mailbox, m_strlen(user) + m_strlen(tmp) + 2);
142       sprintf(a->mailbox, "%s@%s", NONULL (user), NONULL (tmp));
143     }
144
145     p_delete(&domain);
146     p_delete(&user);
147     p_delete(&tmp);
148
149     if (e)
150       return -1;
151   }
152
153   return 0;
154 }
155
156 int mutt_addrlist_to_local (address_t * a)
157 {
158   char *user, *domain;
159   char *tmp = NULL;
160
161   for (; a; a = a->next) {
162     if (!a->mailbox)
163       continue;
164     if (mbox_to_udomain (a->mailbox, &user, &domain) == -1)
165       continue;
166
167     if (mutt_idna_to_local(domain, &tmp, false) == 0) {
168       p_realloc(&a->mailbox, m_strlen(user) + m_strlen(tmp) + 2);
169       sprintf(a->mailbox, "%s@%s", NONULL (user), NONULL (tmp));
170     }
171
172     p_delete(&domain);
173     p_delete(&user);
174     p_delete(&tmp);
175   }
176
177   return 0;
178 }
179
180 /* convert just for displaying purposes */
181 const char *mutt_addr_for_display (address_t * a)
182 {
183   static char *buff = NULL;
184   char *tmp = NULL;
185
186   /* user and domain will be either allocated or reseted to the NULL in
187    * the mbox_to_udomain(), but for safety... */
188   char *domain = NULL;
189   char *user = NULL;
190
191   p_delete(&buff);
192
193   if (mbox_to_udomain (a->mailbox, &user, &domain) != 0)
194     return a->mailbox;
195   if (mutt_idna_to_local (domain, &tmp, true) != 0) {
196     p_delete(&user);
197     p_delete(&domain);
198     p_delete(&tmp);
199     return a->mailbox;
200   }
201
202   p_realloc(&buff, m_strlen(tmp) + m_strlen(user) + 2);
203   sprintf(buff, "%s@%s", NONULL (user), NONULL (tmp));
204   p_delete(&tmp);
205   p_delete(&user);
206   p_delete(&domain);
207   return buff;
208 }
209
210 /* Convert an ENVELOPE structure */
211
212 void mutt_env_to_local (ENVELOPE * e)
213 {
214   mutt_addrlist_to_local (e->return_path);
215   mutt_addrlist_to_local (e->from);
216   mutt_addrlist_to_local (e->to);
217   mutt_addrlist_to_local (e->cc);
218   mutt_addrlist_to_local (e->bcc);
219   mutt_addrlist_to_local (e->reply_to);
220   mutt_addrlist_to_local (e->mail_followup_to);
221 }
222
223 /* Note that `a' in the `env->a' expression is macro argument, not
224  * "real" name of an `env' compound member.  Real name will be substituted
225  * by preprocessor at the macro-expansion time.
226  */
227 #define H_TO_IDNA(a)    \
228   if (mutt_addrlist_to_idna (env->a, err) && !e) \
229   { \
230      if (tag) *tag = #a; e = 1; err = NULL; \
231   }
232
233 int mutt_env_to_idna (ENVELOPE * env, const char **tag, char **err)
234 {
235   int e = 0;
236
237   H_TO_IDNA (return_path);
238   H_TO_IDNA (from);
239   H_TO_IDNA (to);
240   H_TO_IDNA (cc);
241   H_TO_IDNA (bcc);
242   H_TO_IDNA (reply_to);
243   H_TO_IDNA (mail_followup_to);
244   return e;
245 }
246
247 #undef H_TO_IDNA