4978f8f3797315aec0145967bb1772c511ba45ab
[apps/madmutt.git] / lib-mx / pop-new.c
1 /*
2  *  This program is free software; you can redistribute it and/or modify
3  *  it under the terms of the GNU General Public License as published by
4  *  the Free Software Foundation; either version 2 of the License, or (at
5  *  your option) any later version.
6  *
7  *  This program is distributed in the hope that it will be useful, but
8  *  WITHOUT ANY WARRANTY; without even the implied warranty of
9  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
10  *  General Public License for more details.
11  *
12  *  You should have received a copy of the GNU General Public License
13  *  along with this program; if not, write to the Free Software
14  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
15  *  MA 02110-1301, USA.
16  */
17 /*
18  *  Copyright © 2007 Pierre Habouzit
19  *  Copyright © 2000-2002 Vsevolod Volkov <vvv@mutt.org.ua>
20  */
21
22 #include <lib-sys/evtloop.h>
23 #include "pop.h"
24 #include "account.h"
25
26 #define POP3_PORT         110
27 #define POP3S_PORT        995
28
29 enum pop_state {
30     POP_NEW,
31     POP_READY,
32 };
33
34 typedef struct pop_data_t {
35     int refcnt;
36     enum pop_state state;
37
38     volatile job_t *w;
39
40     ACCOUNT act;
41 } pop_data_t;
42 static void pop_data_delete(pop_data_t **tp);
43 DO_ARRAY_TYPE(pop_data_t, pop_data);
44 DO_ARRAY_FUNCS(pop_data_t, pop_data, pop_data_delete);
45
46 /****************************************************************************/
47 /* module                                                                   */
48 /****************************************************************************/
49
50 static pop_data_array conns;
51
52 static inline pop_data_t *pop_data_new(void)
53 {
54     pop_data_t *res = p_new(pop_data_t, 1);
55     res->refcnt = 1;
56     pop_data_array_append(&conns, res);
57     return res;
58 }
59 static inline pop_data_t *pop_data_dup(pop_data_t *t)
60 {
61     t->refcnt++;
62     return t;
63 }
64 static void pop_data_wipe(pop_data_t *pd)
65 {
66     if (pd->w)
67         IGNORE(el_job_release((job_t *)pd->w, EL_KILLED));
68 }
69 static void pop_data_delete(pop_data_t **tp)
70 {
71     if (!*tp)
72         return;
73     if (--(*tp)->refcnt > 0) {
74         *tp = NULL;
75     } else {
76         for (int i = 0; i < conns.len; i++) {
77             if (conns.arr[i] == *tp) {
78                 pop_data_array_take(&conns, i);
79                 break;
80             }
81         }
82         pop_data_wipe(*tp);
83         p_delete(tp);
84     }
85 }
86
87 static __init void pop_initialize(void)
88 {
89     pop_data_array_init(&conns);
90 }
91 static __fini void pop_shutdown(void)
92 {
93     pop_data_array_wipe(&conns);
94 }
95
96 /****************************************************************************/
97 /* pop3 machine                                                             */
98 /****************************************************************************/
99
100 static int pop_setup(job_t *w, void *cfg)
101 {
102     w->ptr = pop_data_dup(cfg);
103     /* FIXME */ return el_job_release(w, EL_ERROR);
104     return 0;
105 }
106
107 static void pop_finalize(job_t *w, el_status reason)
108 {
109     pop_data_delete((pop_data_t **)(void *)&w->ptr);
110 }
111
112 static machine_t const pop_machine = {
113     .name     = "POP3",
114     .setup    = &pop_setup,
115     .finalize = &pop_finalize,
116 };
117
118 /****************************************************************************/
119 /* pop3 mx driver                                                           */
120 /****************************************************************************/
121
122 static int pop_parse_path(const char *path, ACCOUNT *act)
123 {
124     ciss_url_t url;
125     char s[BUFSIZ];
126
127     /* Defaults */
128     act->flags = 0;
129     act->port  = POP3_PORT;
130     act->type  = M_ACCT_TYPE_POP;
131     m_strcpy(s, sizeof(s), path);
132     url_parse_ciss(&url, s);
133
134     if (url.scheme == U_POP || url.scheme == U_POPS) {
135         if (url.scheme == U_POPS) {
136             act->has_ssl = 1;
137             act->port    = POP3S_PORT;
138         }
139
140         if (m_strisempty(url.path) && !mutt_account_fromurl(act, &url))
141             return 0;
142     }
143
144     return -1;
145 }
146
147 static pop_data_t *pop_find_conn(ACCOUNT *act)
148 {
149     pop_data_t *pd = NULL;
150
151     el_lock();
152     for (int i = 0; i < conns.len; i++) {
153         if (mutt_account_match(act, &conns.arr[i]->act)) {
154             pd = pop_data_dup(conns.arr[i]);
155             break;
156         }
157     }
158     if (!pd) {
159         pd = pop_data_new();
160         pd->act = *act;
161     }
162     if (!pd->w) {
163         pd->w = el_job_start(&pop_machine, pd);
164     }
165     while (pd->w && pd->state != POP_READY) {
166         el_wait(pd->w);
167     }
168     if (!pd->w)
169         pop_data_delete(&pd);
170
171     el_unlock();
172     return pd;
173 }
174
175 static int pop_open_mailbox(CONTEXT *ctx)
176 {
177     char buf[BUFSIZ];
178     ACCOUNT act;
179     ciss_url_t url;
180     pop_data_t *pd = NULL;
181
182     if (pop_parse_path(ctx->path, &act)) {
183         mutt_error(_("%s is an invalid POP path"), ctx->path);
184         mutt_sleep(2);
185         return -1;
186     }
187
188     p_clear(&url, 1);
189     mutt_account_tourl(&act, &url);
190
191     pd = pop_find_conn(&act);
192     if (pd) {
193         ctx->data = pd;
194         url_ciss_tostring(&url, buf, sizeof (buf), 0);
195         m_strreplace(&ctx->path, buf);
196     }
197     return 0;
198 }
199
200 mx_t const pop_mx_ng = {
201     .type            = M_POP,
202     .mx_open_mailbox = pop_open_mailbox,
203 };