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