Commit 3211c993 3211c99378cb748df3f7e9334adeceadf0ee4aff by Alain Magloire

not implemented.

1 parent d2ff2875
1 /* GNU mailutils - a suite of utilities for electronic mail
2 Copyright (C) 1999, 2000 Free Software Foundation, Inc.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU Library General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
17
18 #include <errno.h>
19 #include <mailbox0.h>
20 #include <registrar0.h>
21
22
23 static int mailbox_imap_create (mailbox_t *mbox, const char *name);
24 static void mailbox_imap_destroy (mailbox_t *mbox);
25
26 struct mailbox_registrar _mailbox_imap_registrar =
27 {
28 "IMAP4",
29 mailbox_imap_create, mailbox_imap_destroy
30 };
31
32 void
33 mailbox_imap_destroy (mailbox_t *mbox)
34 {
35 (void)mbox;
36 return;
37 }
38
39 int
40 mailbox_imap_create (mailbox_t *mbox, const char *name)
41 {
42 (void)mbox; (void)name;
43 return ENOSYS;
44 }
1 /* GNU mailutils - a suite of utilities for electronic mail
2 Copyright (C) 1999, 2000 Free Software Foundation, Inc.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Library Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
17
18 #include <errno.h>
19 #include <mailbox0.h>
20 #include <registrar0.h>
21
22 static int mailbox_maildir_create (mailbox_t *mbox, const char *name);
23 static void mailbox_maildir_destroy (mailbox_t *mbox);
24
25 struct mailbox_registrar _mailbox_maildir_registrar =
26 {
27 "MAILDIR",
28 mailbox_maildir_create, mailbox_maildir_destroy
29 };
30
31 int
32 mailbox_maildir_create (mailbox_t *mbox, const char *name)
33 {
34 (void)mbox; (void)name;
35 return ENOSYS;
36 }
37
38 void
39 mailbox_maildir_destroy (mailbox_t *mbox)
40 {
41 (void)mbox;
42 return;
43 }
1 /* GNU mailutils - a suite of utilities for electronic mail
2 * Copyright (C) 1999, 2000 Free Software Foundation, Inc.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Library Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19 #include <dirent.h>
20 #include <errno.h>
21 #include <string.h>
22 #include <sys/stat.h>
23 #include <sys/types.h>
24 #include <unistd.h>
25 #include <stdlib.h>
26 #include <ctype.h>
27
28 #include <mailbox0.h>
29 #include <registrar0.h>
30
31 static int mailbox_mh_create (mailbox_t *pmbox, const char *name);
32 static void mailbox_mh_destroy (mailbox_t *pmbox);
33
34 struct mailbox_registrar _mailbox_mh_registrar =
35 {
36 "MH",
37 mailbox_mh_create, mailbox_mh_destroy
38 };
39
40 typedef struct _mh_data
41 {
42 time_t mtime; /* used for checking if mailbox was updated */
43 } mh_data;
44
45 static int mh_open (mailbox_t mbox, int flags);
46 static int mh_close (mailbox_t mbox);
47 static int mh_scan (mailbox_t mbox, size_t msgno, size_t *msgs);
48 static int mh_sequence(const char *name);
49
50 static int
51 mailbox_mh_create (mailbox_t *pmbox, const char *name)
52 {
53 mailbox_t mbox;
54 mh_data *data;
55
56 mbox = malloc(sizeof(*mbox));
57 data = malloc(sizeof(mh_data));
58 mbox->name = malloc(strlen(name) + 1);
59 strcpy(mbox->name, name);
60 mbox->data = data;
61 mbox->_create = mailbox_mh_create;
62 mbox->_destroy = mailbox_mh_destroy;
63 mbox->_open = mh_open;
64 mbox->_close = mh_close;
65 mbox->_scan = mh_scan;
66 *pmbox = mbox;
67
68 return 0;
69 }
70
71 static void
72 mailbox_mh_destroy (mailbox_t *pmbox)
73 {
74 free((*pmbox)->data);
75 free((*pmbox)->name);
76 free(*pmbox);
77 pmbox = NULL;
78 }
79
80 /* FIXME: handle create once the design is ready */
81
82 /* mh_scan actually does all the dirty work */
83 static int
84 mh_open (mailbox_t mbox, int flags)
85 {
86 struct stat st;
87 mh_data *data;
88
89 (void) flags;
90 if (stat(mbox->name, &st) == -1)
91 return errno;
92
93 if (! S_ISDIR(st.st_mode))
94 return EINVAL; /* mailbox is not a directory, thus it is also not MH */
95
96 data = mbox->data;
97 /* FIXME: does mtime change when the dir has a new file added? */
98 data->mtime = st.st_mtime;
99
100 return 0; /* everything is fine */
101 }
102
103 static int
104 mh_close (mailbox_t mbox)
105 {
106 mh_data *data;
107
108 data = mbox->data;
109
110 /* FIXME: implementation */
111 return 0;
112 }
113
114 static int
115 mh_scan (mailbox_t mbox, size_t msgno, size_t *msgs)
116 {
117 struct stat st;
118 DIR *maildir;
119 struct dirent *entry;
120 mh_data *data;
121 unsigned int count = 0;
122 int parse_sequence_file = 0;
123
124 (void)msgno;
125
126 data = mbox->data;
127
128 maildir = opendir(mbox->name);
129
130 while((entry = readdir(maildir)) != NULL) {
131 if(strcmp(".", entry->d_name) == 0 ||
132 strcmp("..", entry->d_name) == 0)
133 continue;
134 /* FIXME: handle this MH extension */
135 if(entry->d_name[0] == '+')
136 continue;
137 /* FIXME: decide what to do with messages marked for removal */
138 if(entry->d_name[0] == ',')
139 continue;
140 if(entry->d_name[0] == '.') {
141 if(strcmp(".mh_sequences", entry->d_name))
142 continue; /* spurious file beginning w/ '.' */
143 else { /* MH info in .mh_sequences */
144 /* FIXME: parse this file */
145 parse_sequence_file = 1;
146 }
147 }
148 if(mh_sequence(entry->d_name)) {
149 /* FIXME: parse file */
150 count++;
151 }
152 }
153 closedir(maildir);
154
155 if(parse_sequence_file && count) {
156 FILE *fp;
157 char *path = malloc(strlen(mbox->name) + strlen(".mh_sequences") + 2);
158 sprintf(path, "%s/.mh_sequences", mbox->name);
159 fp = fopen(path, "r");
160 while(!feof(fp)) {
161 /* FIXME: parse the contents */
162 }
163 fclose(fp);
164 free(path);
165 }
166
167 stat(mbox->name, &st);
168 data->mtime = st.st_mtime;
169
170 if(msgs)
171 *msgs = count;
172 return 0;
173 }
174
175 /*
176 * Local atoi()
177 * created this to guarantee that name is only digits, normal atoi allows
178 * whitespace
179 */
180 static int
181 mh_sequence(const char *name)
182 {
183 const char *sequence;
184 int i;
185
186 for(i = 0, sequence = name; *sequence; sequence++) {
187 if(!isdigit(*sequence))
188 return 0;
189 i *= 10;
190 i += (*sequence - '0');
191 }
192 return i;
193 }
1 /* GNU mailutils - a suite of utilities for electronic mail
2 Copyright (C) 1999, 2000 Free Software Foundation, Inc.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Library Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
17
18 #include <errno.h>
19
20 #include <mailbox0.h>
21 #include <registrar0.h>
22
23 static int mailbox_mmdf_create (mailbox_t *mbox, const char *name);
24 static void mailbox_mmdf_destroy (mailbox_t *mbox);
25
26 struct mailbox_registrar _mailbox_mmdf_registrar =
27 {
28 "MMDF",
29 mailbox_mmdf_create, mailbox_mmdf_destroy
30 };
31
32 static int
33 mailbox_mmdf_create (mailbox_t *mbox, const char *name)
34 {
35 (void)mbox; (void)name;
36 return ENOSYS;
37 }
38
39 static void
40 mailbox_mmdf_destroy (mailbox_t *mbox)
41 {
42 (void)mbox;
43 return;
44 }
1 /* GNU mailutils - a suite of utilities for electronic mail
2 Copyright (C) 1999, 2000 Free Software Foundation, Inc.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Library Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
17
18 /* First draft by Alain Magloire */
19
20 #include <mailbox0.h>
21 #include <registrar0.h>
22 #include <message0.h>
23 #include <url0.h>
24 #include <stream0.h>
25 #include <body0.h>
26 #include <header0.h>
27 #include <attribute0.h>
28 #include <mailutils/header.h>
29 #include <mailutils/auth.h>
30 #include <mailutils/locker.h>
31
32 //#define HAVE_PTHREAD_H
33
34 #include <stdlib.h>
35 #include <stdio.h>
36 #include <time.h>
37 #include <sys/stat.h>
38 #include <fcntl.h>
39 #include <unistd.h>
40 #include <signal.h>
41 #include <time.h>
42 #ifdef HAVE_PTHREAD_H
43 # include <pthread.h>
44 #else
45 # define flockfile(arg)
46 # define funlockfile(arg)
47 #endif
48 #include <string.h>
49 #include <ctype.h>
50 #include <limits.h>
51 #include <errno.h>
52
53 #define ATTRIBUTE_IS_DELETED(flag) (flag & MU_ATTRIBUTE_DELETED)
54 #define ATTRIBUTE_IS_EQUAL(flag1, flag2) (flag1 == flag2)
55
56 struct _unix_message;
57 struct _unix_data;
58
59 typedef struct _unix_data* unix_data_t;
60 typedef struct _unix_message* unix_message_t;
61
62 static int unix_create (mailbox_t *pmbox, const char *name);
63 static void unix_destroy (mailbox_t *pmbox);
64
65 struct mailbox_registrar _mailbox_unix_registrar =
66 {
67 "UNIX MBOX",
68 unix_create, unix_destroy
69 };
70
71 /* Keep the position of where the header and body starts and ends.
72 old_flags is the "Status:" message. */
73 struct _unix_message
74 {
75 /* Offset of the parts of the messages in the mailbox. */
76 off_t header_from;
77 off_t header_from_end;
78 /* Little hack to make things easier * when updating the attribute. */
79 off_t header_status;
80 off_t header_status_end;
81 off_t body;
82 off_t body_end;
83
84 /* The old_flags contains the definition of Header. */
85 int old_flags;
86 /* The new_flags holds the attributes changes for the current session. We
87 use this so when expunging we can tell when an attribute been modified.
88 This is a big help so we can jump to the first modify email for speed
89 in expunging (see mark dirty). */
90 int new_flags;
91
92 size_t header_lines;
93 size_t body_lines;
94 stream_t stream;
95
96 /* A message attach to it. */
97 message_t message;
98
99 };
100
101 /* The umessages is an array of pointers that contains umessages_count of
102 unix_message_t*; umessages[umessages_count]. We do it this because
103 realloc() can move everything to a new memory region and invalidating all
104 the pointers someone has on the messages. Thanks to <Dave Inglis> for
105 pointing this out. The messages_count is the count number of messages
106 parsed so far. */
107 struct _unix_data
108 {
109 unix_message_t *umessages;
110 size_t umessages_count;
111 size_t messages_count;
112 stream_t stream;
113 #ifdef HAVE_PTHREAD_H
114 pthread_mutex_t mutex;
115 #endif
116 off_t size;
117
118 /* The variables below are use to hold the state when appending messages. */
119 enum unix_state
120 {
121 UNIX_NO_STATE=0, UNIX_STATE_FROM, UNIX_STATE_DATE, UNIX_STATE_APPEND
122 } state ;
123 char *from;
124 char *date;
125 off_t off;
126
127 };
128
129 /* Mailbox implementation. */
130 static int unix_open (mailbox_t mbox, int flag);
131 static int unix_close (mailbox_t mbox);
132 static int unix_get_message (mailbox_t, size_t msgno, message_t *msg);
133 static int unix_append_message (mailbox_t, message_t msg);
134 static int unix_messages_count (mailbox_t, size_t *msgno);
135 static int unix_expunge (mailbox_t);
136 static int unix_num_deleted (mailbox_t, size_t *);
137 static int unix_scan (mailbox_t, size_t count, size_t *pcount);
138 static int unix_is_updated (mailbox_t);
139 static int unix_size (mailbox_t, off_t *size);
140
141
142 /* private stuff */
143 static int unix_scan0 (mailbox_t, size_t count, size_t *pcount, int);
144 static int unix_get_header_read (stream_t is, char *buffer, size_t len,
145 off_t off, size_t *pnread);
146 static int unix_get_fd (stream_t is, int *pfd);
147 static int unix_get_flags (attribute_t, int *);
148 static int unix_set_flags (attribute_t, int);
149 static int unix_unset_flags (attribute_t, int);
150 static int unix_readstream (stream_t is, char *buffer, size_t buflen,
151 off_t off, size_t *pnread);
152 static int unix_header_size (header_t header, size_t *psize);
153 static int unix_header_lines (header_t header, size_t *plines);
154 static int unix_body_size (body_t body, size_t *psize);
155 static int unix_body_lines (body_t body, size_t *plines);
156 static int unix_msg_from (message_t msg, char *buf, size_t len,
157 size_t *pnwrite);
158 static int unix_msg_received (message_t msg, char *buf, size_t len,
159 size_t *pnwrite);
160 static int unix_lock (mailbox_t mbox, int flag);
161 static int unix_touchlock (mailbox_t mbox);
162 static int unix_unlock (mailbox_t mbox);
163 static int unix_ilock (mailbox_t mbox, int flag);
164 static int unix_iunlock (mailbox_t mbox);
165
166 /* We allocate the mailbox_t struct, but don't do any parsing on the name or
167 even test for existence. However we do strip any leading "unix:" part of
168 the name, this is suppose to be the protocol/scheme name. Hopefully there
169 will not be a mailbox name "unix:". */
170 static int
171 unix_create (mailbox_t *pmbox, const char *name)
172 {
173 mailbox_t mbox;
174 unix_data_t mud;
175 size_t name_len;
176
177 /* Sanity check. */
178 if (name == NULL || *name == '\0')
179 return EINVAL;
180
181 name_len = strlen (name);
182
183 #define UNIX_SCHEME "unix:"
184 #define UNIX_SCHEME_LEN 5
185 #define SEPARATOR '/'
186
187 /* Skip the url scheme. */
188 if (name_len > UNIX_SCHEME_LEN
189 && (name[0] == 'u' || name[0] == 'U')
190 && (name[1] == 'n' || name[1] == 'N')
191 && (name[2] == 'i' || name[2] == 'i')
192 && (name[3] == 'x' || name[3] == 'x' )
193 && name[4] == ':')
194 {
195 name += UNIX_SCHEME_LEN;
196 name_len -= UNIX_SCHEME_LEN;
197 }
198
199 /* Allocate memory for mbox (mailbox_t). */
200 mbox = calloc (1, sizeof (*mbox));
201 if (mbox == NULL)
202 return ENOMEM;
203
204 /* Allocate specific unix mbox data. */
205 mud = mbox->data = calloc (1, sizeof (*mud));
206 if (mbox->data == NULL)
207 {
208 unix_destroy (&mbox);
209 return ENOMEM;
210 }
211
212 /* Copy the name.
213 We do not do any further interpretation after the scheme "unix:"
214 Because for example on distributed system like QnX4 a file name is
215 //390/etc/passwd. So the best approach is to let the OS handle it
216 for example if we receive: "unix:///var/mail/alain" the mailbox name
217 will be "///var/mail/alain" we let open() do the right thing.
218 So it will let things like this "unix://390/var/mail/alain" where
219 "//390/var/mail/alain" _is_ the filename, pass correctely. */
220 mbox->name = calloc (name_len + 1, sizeof (char));
221 if (mbox->name == NULL)
222 {
223 unix_destroy (&mbox);
224 return ENOMEM;
225 }
226 memcpy (mbox->name, name, name_len);
227
228 #ifdef HAVE_PHTREAD_H
229 /* Mutex when accessing the structure fields. */
230 /* FIXME: should we use rdwr locks instead ?? */
231 pthread_mutex_init (&(mbox->mutex), NULL);
232 #endif
233
234 mbox->_create = unix_create;
235 mbox->_destroy = unix_destroy;
236
237 mbox->_open = unix_open;
238 mbox->_close = unix_close;
239
240 /* Messages. */
241 mbox->_get_message = unix_get_message;
242 mbox->_append_message = unix_append_message;
243 mbox->_messages_count = unix_messages_count;
244 mbox->_expunge = unix_expunge;
245 mbox->_num_deleted = unix_num_deleted;
246
247 mbox->_scan = unix_scan;
248 mbox->_is_updated = unix_is_updated;
249
250 mbox->_size = unix_size;
251
252 mailbox_debug (mbox, MU_MAILBOX_DEBUG_TRACE, "unix_create(%s)\n",
253 mbox->name);
254 (*pmbox) = mbox;
255
256 return 0; /* okdoke */
257 }
258
259 /* Free all ressources associated with Unix mailbox. */
260 static void
261 unix_destroy (mailbox_t *pmbox)
262 {
263 if (pmbox && *pmbox)
264 {
265 mailbox_t mbox = *pmbox;
266 unix_close (mbox);
267 if (mbox->data)
268 {
269 size_t i;
270 unix_data_t mud = mbox->data;
271 mailbox_debug (mbox, MU_MAILBOX_DEBUG_TRACE,
272 "unix_destroy (%s/%s)\n", mbox->name);
273 for (i = 0; i < mud->umessages_count; i++)
274 {
275 unix_message_t mum = mud->umessages[i];
276 if (mum == NULL)
277 {
278 message_destroy (&(mum->message), mum);
279 free (mum);
280 }
281 }
282 free (mud->umessages);
283 free (mbox->data);
284 }
285 free (mbox->name);
286 /* Free the event array. */
287 free (mbox->event);
288 /* Destroy the url. */
289 if (mbox->url)
290 url_destroy (&(mbox->url));
291 if (mbox->locker)
292 locker_destroy (&(mbox->locker));
293 if (mbox->auth)
294 auth_destroy (&(mbox->auth), mbox);
295 if(mbox->stream)
296 stream_destroy (&(mbox->stream), mbox);
297 unix_iunlock (mbox);
298 #ifdef HAVE_PTHREAD_H
299 if (mbox->mutex)
300 ptread_mutex_destroy (&(mbox->mutex));
301 #endif
302 free (mbox);
303 *pmbox = NULL;
304 }
305 }
306
307 /* Open the file. */
308 static int
309 unix_open (mailbox_t mbox, int flags)
310 {
311 unix_data_t mud = mbox->data;
312 int status = 0;
313
314 if (mud == NULL)
315 return EINVAL;
316
317 /* Authentication prologues. */
318 if (mbox->auth)
319 auth_prologue (mbox->auth);
320
321 /* Get a stream. */
322 if (mbox->stream == NULL)
323 {
324 /* FIXME: for small mbox we shout try to mmap (). */
325
326 status = (flags & MU_STREAM_CREAT) || (flags & MU_STREAM_APPEND);
327 if (status == 0)
328 status = mapfile_stream_create (&(mbox->stream));
329 if (status != 0)
330 {
331 status = file_stream_create (&(mbox->stream));
332 if (status != 0)
333 return status;
334 }
335 status = stream_open (mbox->stream, mbox->name, 0, flags);
336 if (status != 0)
337 return status;
338 }
339 else
340 {
341 status = stream_open (mbox->stream, mbox->name, 0, flags);
342 if (status != 0)
343 return status;
344 }
345
346 /* Authentication epilogue. */
347 if (mbox->auth)
348 auth_epilogue (mbox->auth);
349
350 mailbox_debug (mbox, MU_MAILBOX_DEBUG_TRACE, "unix_open(%s, %d)\n",
351 mbox->name, flags);
352
353 /* Give an appopriate way to lock. */
354 if (mbox->locker == NULL)
355 locker_create (&(mbox->locker), mbox->name, strlen (mbox->name),
356 MU_LOCKER_PID | MU_LOCKER_FCNTL);
357 return 0;
358 }
359
360 static int
361 unix_close (mailbox_t mbox)
362 {
363 unix_data_t mud = mbox->data;
364 size_t i;
365
366 if (mud == NULL)
367 return EINVAL;
368
369 /* Make sure we do not hold any lock for that file. */
370 unix_unlock (mbox);
371 mailbox_debug (mbox, MU_MAILBOX_DEBUG_TRACE, "unix_close(%s)\n",
372 mbox->name);
373
374 /* Before closing we need to remove all the messages
375 - to reclaim the memory
376 - to prepare for another scan. */
377 for (i = 0; i < mud->umessages_count; i++)
378 {
379 unix_message_t mum = mud->umessages[i];
380 /* Destroy the attach messages. */
381 if (mum == NULL)
382 {
383 message_destroy (&(mum->message), mum);
384 free (mum);
385 }
386 }
387 free (mud->umessages);
388 mud->umessages = NULL;
389 mud->messages_count = mud->umessages_count = 0;
390 mud->size = 0;
391 return stream_close (mbox->stream);
392 }
393
394 /* Mailbox Parsing. */
395 #include "mbx_unixscan.c"
396
397 static int
398 unix_scan (mailbox_t mbox, size_t msgno, size_t *pcount)
399 {
400 mailbox_debug (mbox, MU_MAILBOX_DEBUG_TRACE, "unix_scan(%s)\n", mbox->name);
401 return unix_scan0 (mbox, msgno, pcount, 1);
402 }
403
404
405 /* FIXME: How to handle a shrink ? meaning, the &^$^@%#@^& user start two
406 browsers and delete files in one. My views is that we should scream
407 bloody murder and hunt them with a machette. But for now just play dumb,
408 but maybe the best approach is to pack our things and leave .i.e exit(). */
409 static int
410 unix_is_updated (mailbox_t mbox)
411 {
412 off_t size;
413 unix_data_t mud = mbox->data;
414
415 if (mud == NULL)
416 return EINVAL;
417 if (stream_size (mbox->stream, &size) != 0)
418 return 0;
419 return (mud->size == size);
420 }
421
422 static int
423 unix_num_deleted (mailbox_t mbox, size_t *pnum)
424 {
425 unix_data_t mud = mbox->data;
426 unix_message_t mum;
427 size_t i, total;
428 if (mud == NULL)
429 return EINVAL;
430 for (i = total = 0; i < mud->messages_count; i++)
431 {
432 mum = mud->umessages[i];
433 if (ATTRIBUTE_IS_DELETED (mum->new_flags))
434 total++;
435 }
436
437 if (pnum)
438 *pnum = total;
439 return 0;
440 }
441
442 /* FIXME: the use of tmpfile() on some system can lead to race condition, We
443 should use a safer approach. */
444 static FILE *
445 unix_tmpfile (mailbox_t mbox, char **pbox)
446 {
447 const char *tmpdir;
448 int fd;
449 FILE *fp;
450 const char *basename;
451
452 /* P_tmpdir should be define in <stdio.h>. */
453 #ifndef P_tmpdir
454 # define P_tmpdir "/tmp"
455 #endif
456
457 tmpdir = getenv ("TEMPDIR") ? getenv ("TEMPDIR") : P_tmpdir;
458 basename = strrchr (mbox->name, '/');
459 if (basename)
460 basename++;
461 else
462 basename = mbox->name;
463 *pbox = calloc (strlen (tmpdir) + strlen ("MBOX_") +
464 strlen (basename) + 1, sizeof (char));
465 if (*pbox == NULL)
466 return NULL;
467 sprintf (*pbox, "%s/%s%s", tmpdir, "MBOX_", basename);
468
469 /* FIXME: I don't think this is the righ approach, creating an anonymous
470 file would be better ? no trace left behind. */
471 /* Create the file. It must not exist. If it does exist, fail. */
472 fd = open (*pbox, O_RDWR|O_CREAT|O_EXCL, 0600);
473 if (fd < 0)
474 {
475 fprintf (stderr,"Can't create %s\n", *pbox);
476 fprintf (stderr,"delete file <%s>, Please\n", *pbox);
477 fprintf (stderr, "It was likely due to an error when expunging\n");
478 return NULL;
479 }
480 fp = fdopen (fd, "w+");
481 if (fp == 0)
482 {
483 close(fd);
484 free (*pbox);
485 *pbox = NULL;
486 }
487
488 /* Really I should just remove the file here. */
489 /* remove(*pbox); */
490 return fp;
491 }
492
493 /* For the expunge bits we took a very cautionnary approach, meaning
494 we create temporary file in the tmpdir copy all the file not mark deleted,
495 and skip the deleted ones, truncate the real mailbox to the desired size
496 and overwrite with the tmp mailbox. The approach to do everyting
497 in core is tempting but require to much memory, it is not rare now
498 a day to have 30 Megs mailbox, also there is danger for filesystems
499 with quotas, or some program may not respect the advisory lock and
500 decide to append a new message while your expunging etc ...
501 The real downside to the approach we take is that when things go wrong
502 the temporary file bay be left in /tmp, which is not all that bad
503 because at least have something to recuparate when failure. */
504 static int
505 unix_expunge (mailbox_t mbox)
506 {
507 unix_data_t mud = mbox->data;
508 unix_message_t mum;
509 int status = 0;
510 sigset_t sigset;
511 FILE *tempfile;
512 size_t nread;
513 size_t i, j, dirty, first;
514 off_t marker = 0;
515 off_t total = 0;
516 char buffer [BUFSIZ];
517 char *tmpmbox = NULL;
518
519 if (mud == NULL)
520 return EINVAL;
521
522 /* Noop. */
523 if (mud->messages_count == 0)
524 return 0;
525
526 /* Do we have a consistent view of the mailbox. */
527 /* FIXME: this is not enough, we can do better
528 - by checking the file size and scream bloody murder if it has shrink.
529 - if its bigger we should be able to handle it before the ftruncate ()
530 by copying back the new messages. */
531 if (! unix_is_updated (mbox))
532 {
533 fprintf (stderr, "mailbox is not updated, try again.\n");
534 return EAGAIN;
535 }
536
537 /* Mark dirty the first mail with an attribute change. */
538 for (dirty = 0; dirty < mud->messages_count; dirty++)
539 {
540 mum = mud->umessages[dirty];
541 if (mum->new_flags &&
542 ! ATTRIBUTE_IS_EQUAL (mum->old_flags, mum->new_flags))
543 break;
544 }
545
546 /* Did something change ? */
547 if (dirty == mud->messages_count)
548 return 0; /* Nothing change, bail out. */
549
550 mailbox_debug (mbox, MU_MAILBOX_DEBUG_TRACE, "unix_expunge (%s)\n",
551 mbox->name);
552
553 /* This is redundant, we go to the loop again. But it's more secure here
554 since we don't want to be disturb when expunging. */
555 for (j = 0; j < mud->messages_count; j++)
556 {
557 mum = mud->umessages[j];
558 if (mum && mum->new_flags && ATTRIBUTE_IS_DELETED (mum->new_flags))
559 message_destroy (&(mum->message), mum);
560 }
561
562 /* Create a tempory file. */
563 tempfile = unix_tmpfile (mbox, &tmpmbox);
564 if (tempfile == NULL)
565 {
566 fprintf (stderr, "Failed to create temporary file when expunging.\n");
567 free (tmpmbox);
568 return errno;
569 }
570
571 /* Get the lock. */
572 if (unix_lock (mbox, MU_LOCKER_WRLOCK) < 0)
573 {
574 fclose (tempfile);
575 remove (tmpmbox);
576 free (tmpmbox);
577 fprintf (stderr, "Failed to grab the lock\n");
578 return ENOLCK;
579 }
580
581 /* Critical section, we can not allowed signal here. */
582 sigemptyset (&sigset);
583 sigaddset (&sigset, SIGTERM);
584 sigaddset (&sigset, SIGHUP);
585 sigaddset (&sigset, SIGTSTP);
586 sigaddset (&sigset, SIGINT);
587 sigaddset (&sigset, SIGWINCH);
588 sigprocmask (SIG_BLOCK, &sigset, 0);
589
590 unix_ilock (mbox, MU_LOCKER_RDLOCK);
591
592 /* Set the marker position. */
593 total = marker = mud->umessages[dirty]->header_from;
594
595 /* Copy to tempfile emails not mark deleted. */
596 for (first = 1, i = dirty; i < mud->messages_count; i++)
597 {
598 mum = mud->umessages[i];
599
600 /* Skip it, if mark for deletion. */
601 if (ATTRIBUTE_IS_DELETED (mum->new_flags))
602 continue;
603
604 /* Add a NL separator between messages. */
605 if (first)
606 first = 0;
607 else
608 {
609 fputc ('\n', tempfile);
610 total++;
611 }
612
613 /* Begining of header copy. */
614 {
615 off_t current;
616 /* This is done in two parts first we check if the attribute changed,
617 if yes then we have to update the "Status:" field. Unfortunately
618 there is no requirement for the "Status:" to be the last field, so
619 we take the long approach; Copy up to the Status, update the
620 Status and copy the rest. */
621
622 /* Attribute change ? */
623 if (mum->new_flags
624 &&! ATTRIBUTE_IS_EQUAL (mum->old_flags, mum->new_flags)
625 && mum->header_status > mum->header_from)
626 {
627 size_t n = 0;
628 off_t offset = mum->header_from;
629 size_t len = mum->header_status - mum->header_from;
630 current = mum->header_status_end;
631 while (len > 0)
632 {
633 nread = (len < sizeof (buffer)) ? len : sizeof (buffer);
634 if ((status = stream_read (mbox->stream, buffer,
635 nread, offset, &n) != 0)
636 || fwrite(buffer, sizeof(*buffer), n, tempfile) != n)
637 {
638 if (status == 0)
639 status = errno;
640 fprintf (stderr, "Error expunge:%d: (%s)\n", __LINE__,
641 strerror (status));
642 goto bailout0;
643 }
644 len -= n;
645 total += n;
646 offset += n;
647 }
648
649 /* Put the new attributes. */
650 {
651 char abuf[64];
652 size_t na = 0;
653 abuf[0] = '\0';
654 flags_to_string (mum->new_flags, abuf, sizeof(abuf), &na);
655 fputs (abuf, tempfile);
656 total += na;
657 }
658 }
659 else /* Attribute did not change. */
660 current = mum->header_from;
661
662 /* Copy the rest of header without changes. */
663 {
664 size_t n = 0;
665 off_t offset = current;
666 size_t len = mum->body - current;
667 while (len > 0)
668 {
669 nread = (len < sizeof (buffer)) ? len : sizeof (buffer);
670 if ((status = stream_read (mbox->stream, buffer, nread,
671 offset, &n) != 0)
672 || fwrite(buffer, sizeof(*buffer), n, tempfile) != n)
673 {
674 if (status == 0)
675 status = errno;
676 fprintf (stderr, "Error expunge:%d: %s", __LINE__,
677 strerror (status));
678 goto bailout0;
679 }
680 len -= n;
681 total += n;
682 offset += n;
683 }
684 }
685 } /* End of header copy. */
686
687 /* Copy the body. */
688 {
689 size_t n = 0;
690 off_t offset = mum->body;
691 size_t len = mum->body_end - mum->body;
692 while (len > 0)
693 {
694 nread = (len < sizeof (buffer)) ? len : sizeof (buffer);
695 if ((status = stream_read (mbox->stream, buffer, nread,
696 offset, &n) != 0)
697 || fwrite(buffer, sizeof(*buffer), n, tempfile) != n)
698 {
699 if (status == 0)
700 status = errno;
701 fprintf (stderr, "Error expunge:%d: %s", __LINE__,
702 strerror (status));
703 goto bailout0;
704 }
705 len -= n;
706 total += n;
707 offset += n;
708 }
709 } /* End of body copy. */
710 } /* for (;;) */
711
712 /* Caution: before ftruncate()ing the file see if we've receiving new mail
713 Some program may not respect the lock, or the lock was held for too
714 long. */
715 {
716 off_t size = 0;
717 if (stream_size (mbox->stream, &size) == 0)
718 {
719 size_t n = 0;
720 off_t offset = size;
721 size_t len = size - mud->size;
722 while (len > 0)
723 {
724 nread = (len < sizeof (buffer)) ? len : sizeof (buffer);
725 if ((status = stream_read (mbox->stream, buffer, nread,
726 offset, &n) != 0)
727 || fwrite(buffer, sizeof(*buffer), n, tempfile) != n)
728 {
729 if (status == 0)
730 status = errno;
731 fprintf (stderr, "Error expunge:%d: %s", __LINE__,
732 strerror (status));
733 goto bailout0;
734 }
735 len -= n;
736 total += n;
737 offset += n;
738 }
739 }
740 } /* End of precaution. */
741
742 /* Seek and rewrite it. */
743 rewind (tempfile);
744 if (total > 0)
745 {
746 size_t n = 0;
747 off_t offset = marker;
748 while ((nread = fread (buffer, sizeof (*buffer),
749 sizeof (buffer), tempfile)) != 0)
750 {
751 while (nread)
752 {
753 status = stream_write (mbox->stream, buffer, nread, offset, &n);
754 if (status != 0)
755 {
756 fprintf (stderr, "Error expunge:%d: %s\n", __LINE__,
757 strerror (status));
758 goto bailout;
759 }
760 nread -= n;
761 offset += n;
762 }
763 }
764 }
765
766 /* How can I handle error here ?? */
767 clearerr (tempfile);
768
769 /* Flush/truncation. */
770 stream_flush (mbox->stream);
771 status = stream_truncate (mbox->stream, total);
772 if (status != 0)
773 {
774 fprintf (stderr, "Error expunging:%d: %s", __LINE__, strerror (status));
775 goto bailout;
776 }
777
778 bailout0:
779 /* Don't remove the tmp mbox in case of errors, when writing back. */
780 remove (tmpmbox);
781
782 bailout:
783
784 free (tmpmbox);
785 /* Release the locks. */
786 unix_unlock (mbox);
787 unix_iunlock (mbox);
788 fclose (tempfile);
789 sigprocmask (SIG_UNBLOCK, &sigset, 0);
790
791 /* We need to readjust the pointers. */
792 if (status == 0)
793 {
794 size_t dlast;
795 for (j = dirty, dlast = mud->messages_count - 1;
796 j < mud->messages_count; j++)
797 {
798 /* Clear all the references, any attach messages been already
799 destroy above. */
800 mum = mud->umessages[j];
801 if (mum->new_flags && ATTRIBUTE_IS_DELETED (mum->new_flags))
802 {
803 memmove (mud->umessages + j, mud->umessages + j + 1,
804 (dlast - dirty) * sizeof (mum));
805 mum->header_from = mum->header_from_end = 0;
806 mum->header_status = mum->header_status_end = 0;
807 mum->body = mum->body_end = 0;
808 mum->header_lines = mum->body_lines = 0;
809 mud->umessages[dlast] = mum;
810 dlast--;
811 mum = mud->umessages[j];
812 }
813 mum->header_from = mum->header_from_end = 0;
814 mum->header_status = mum->header_status_end = 0;
815 mum->body = mum->body_end = 0;
816 mum->header_lines = mum->body_lines = 0;
817 }
818 /* This is should reset the messages_count, the last argument 0 means
819 not to send event notification. */
820 unix_scan0 (mbox, dirty, NULL, 0);
821 }
822 return status;
823 }
824
825 static int
826 unix_get_fd (stream_t is, int *pfd)
827 {
828 unix_message_t mum = is->owner;
829
830 if (mum == NULL)
831 return EINVAL;
832
833 return stream_get_fd (mum->stream, pfd);
834 }
835
836 static int
837 unix_get_flags (attribute_t attr, int *pflags)
838 {
839 unix_message_t mum = attr->owner;
840
841 if (mum == NULL)
842 return EINVAL;
843
844 if (pflags)
845 *pflags = mum->new_flags;
846 return 0;
847 }
848
849 static int
850 unix_set_flags (attribute_t attr, int flags)
851 {
852 unix_message_t mum = attr->owner;
853
854 if (mum == NULL)
855 return EINVAL;
856
857 mum->new_flags |= flags;
858 return 0;
859 }
860
861 static int
862 unix_unset_flags (attribute_t attr, int flags)
863 {
864 unix_message_t mum = attr->owner;
865
866 if (mum == NULL)
867 return EINVAL;
868
869 mum->new_flags &= ~flags;
870 return 0;
871 }
872
873 static int
874 unix_readstream (stream_t is, char *buffer, size_t buflen,
875 off_t off, size_t *pnread)
876 {
877 unix_message_t mum = is->owner;
878 size_t nread = 0;
879
880 if (mum == NULL)
881 return EINVAL;
882
883 if (buffer == NULL || buflen == 0)
884 {
885 if (pnread)
886 *pnread = nread;
887 return 0;
888 }
889
890 {
891 off_t ln = mum->body_end - (mum->body + off);
892 size_t n = 0;
893 int status;
894 if (ln > 0)
895 {
896 nread = ((size_t)ln < buflen) ? ln : buflen;
897 /* Position the file pointer and the buffer. */
898 status = stream_read (mum->stream, buffer, nread, mum->body + off, &n);
899 if (status != 0)
900 return status;
901 }
902 }
903
904 if (pnread)
905 *pnread = nread;
906 return 0;
907 }
908
909 static int
910 unix_get_header_read (stream_t is, char *buffer, size_t len,
911 off_t off, size_t *pnread)
912 {
913 unix_message_t mum = is->owner;
914 size_t nread = 0;
915 int status = 0;
916 off_t ln;
917
918 if (mum == NULL)
919 return EINVAL;
920
921 ln = mum->body - (mum->header_from_end + off);
922 if (ln > 0)
923 {
924 nread = ((size_t)ln < len) ? ln : len;
925 /* Position the file pointer and the buffer. */
926 status = stream_read (mum->stream, buffer, nread,
927 mum->header_from_end + off, &nread);
928 }
929 if (pnread)
930 *pnread = nread;
931 return status;
932 }
933
934 static int
935 unix_header_size (header_t header, size_t *psize)
936 {
937 unix_message_t mum = header->owner;
938 if (mum == NULL)
939 return EINVAL;
940 if (psize)
941 *psize = mum->body - mum->header_from_end;
942 return 0;
943 }
944
945 static int
946 unix_header_lines (header_t header, size_t *plines)
947 {
948 unix_message_t mum = header->owner;
949 if (mum == NULL)
950 return EINVAL;
951 if (plines)
952 *plines = mum->header_lines;
953 return 0;
954 }
955
956 static int
957 unix_body_size (body_t body, size_t *psize)
958 {
959 unix_message_t mum = body->owner;
960 if (mum == NULL)
961 return EINVAL;
962 if (psize)
963 *psize = mum->body_end - mum->body + 1;
964 return 0;
965 }
966
967 static int
968 unix_body_lines (body_t body, size_t *plines)
969 {
970 unix_message_t mum = body->owner;
971 if (mum == NULL)
972 return EINVAL;
973 if (plines)
974 *plines = mum->body_lines;
975 return 0;
976 }
977
978 static int
979 unix_msg_received (message_t msg, char *buf, size_t len,
980 size_t *pnwrite)
981 {
982 unix_message_t mum = msg->owner;
983 size_t n = 0;
984 int status;
985 char buffer[512];
986
987 if (mum == NULL)
988 return EINVAL;
989
990 status = stream_readline (mum->stream, buffer, sizeof(buffer),
991 mum->header_from, &n);
992 if (status != 0)
993 {
994 if (pnwrite)
995 *pnwrite = 0;
996 if (buf)
997 *buf = '\0';
998 return status;
999 }
1000
1001 if (n > 5)
1002 {
1003 char *s = strchr (buffer + 5, ' ');
1004 if (s)
1005 {
1006 if (buf && len > 0)
1007 {
1008 strncpy (buf, s + 1, len);
1009 buffer [len - 1] = '\0';
1010 }
1011 if (pnwrite)
1012 *pnwrite = strlen (s + 1);
1013 return 0;
1014 }
1015 }
1016 if (pnwrite)
1017 *pnwrite = 0;
1018 if (buf)
1019 *buf = '\0';
1020 return 0;
1021 }
1022
1023 static int
1024 unix_msg_from (message_t msg, char *buf, size_t len, size_t *pnwrite)
1025 {
1026 unix_message_t mum = msg->owner;
1027 size_t n = 0;
1028 int status;
1029 char buffer[512];
1030
1031 if (mum == NULL)
1032 return EINVAL;
1033
1034 status = stream_readline (mum->stream, buffer, sizeof(buffer),
1035 mum->header_from, &n);
1036 if (status != 0)
1037 {
1038 if (pnwrite)
1039 *pnwrite = 0;
1040 if (buf)
1041 *buf = '\0';
1042 return status;
1043 }
1044
1045 if (n > 5)
1046 {
1047 char *s = strchr (buffer + 5, ' ');
1048 if (s)
1049 {
1050 *s = '\0';
1051 if (buf && len > 0)
1052 {
1053 strncpy (buf, buffer + 5, len);
1054 buffer [len - 1] = '\0';
1055 }
1056 if (pnwrite)
1057 *pnwrite = strlen (buffer + 5);
1058 return 0;
1059 }
1060 }
1061 if (pnwrite)
1062 *pnwrite = 0;
1063 if (buf)
1064 *buf = '\0';
1065 return 0;
1066 }
1067
1068 static int
1069 unix_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg)
1070 {
1071 int status;
1072 unix_data_t mud = mbox->data;
1073 unix_message_t mum;
1074 message_t msg = NULL;
1075
1076 /* Sanity checks. */
1077 if (pmsg == NULL || mud == NULL || (!(mud->messages_count > 0 && msgno > 0
1078 && msgno <= mud->messages_count)))
1079 return EINVAL;
1080
1081 mum = mud->umessages[msgno - 1];
1082
1083 /* Check if we already have it. */
1084 if (mum->message)
1085 {
1086 if (pmsg)
1087 *pmsg = mum->message;
1088 return 0;
1089 }
1090
1091 mailbox_debug (mbox, MU_MAILBOX_DEBUG_TRACE,
1092 "unix_get_message(%s, %d)\n", mbox->name, msgno);
1093
1094 /* Get an empty message struct. */
1095 status = message_create (&msg, mum);
1096 if (status != 0)
1097 return status;
1098
1099 /* Set the header. */
1100 {
1101 header_t header = NULL;
1102 stream_t stream = NULL;
1103 if ((status = header_create (&header, NULL, 0, mum)) != 0
1104 || (status = stream_create (&stream, MU_STREAM_READ, mum)) != 0)
1105 {
1106 stream_destroy (&stream, mum);
1107 header_destroy (&header, mum);
1108 message_destroy (&msg, mum);
1109 return status;
1110 }
1111 stream_set_read (stream, unix_get_header_read, mum);
1112 stream_set_fd (stream, unix_get_fd, mum);
1113 stream_set_flags (stream, MU_STREAM_READ, mum);
1114 header_set_stream (header, stream, mum);
1115 header_set_size (header, unix_header_size, mum);
1116 header_set_lines (header, unix_header_lines, mum);
1117 message_set_header (msg, header, mum);
1118 }
1119
1120 /* Set the attribute. */
1121 {
1122 attribute_t attribute;
1123 status = attribute_create (&attribute, mum);
1124 if (status != 0)
1125 {
1126 message_destroy (&msg, mum);
1127 return status;
1128 }
1129 mum->new_flags = mum->old_flags;
1130 attribute_set_get_flags (attribute, unix_get_flags, mum);
1131 attribute_set_set_flags (attribute, unix_set_flags, mum);
1132 attribute_set_unset_flags (attribute, unix_unset_flags, mum);
1133 message_set_attribute (msg, attribute, mum);
1134 }
1135
1136 /* Prepare the body. */
1137 {
1138 body_t body = NULL;
1139 stream_t stream = NULL;
1140 int flags = MU_STREAM_READ;
1141 if ((status = body_create (&body, mum)) != 0
1142 || (status = stream_create (&stream, flags, mum)) != 0)
1143 {
1144 body_destroy (&body, mum);
1145 stream_destroy (&stream, mum);
1146 message_destroy (&msg, mum);
1147 return status;
1148 }
1149 stream_set_read (stream, unix_readstream, mum);
1150 stream_set_fd (stream, unix_get_fd, mum);
1151 stream_get_flags (mbox->stream, &flags);
1152 stream_set_flags (stream, flags, mum);
1153 body_set_stream (body, stream, mum);
1154 body_set_size (body, unix_body_size, mum);
1155 body_set_lines (body, unix_body_lines, mum);
1156 message_set_body (msg, body, mum);
1157 }
1158
1159 /* Set the envelope. */
1160 message_set_from (msg, unix_msg_from, mum);
1161 message_set_received (msg, unix_msg_received, mum);
1162
1163 /* Attach the message to the mailbox unix data. */
1164 mum->message = msg;
1165
1166 if (pmsg)
1167 *pmsg = msg;
1168 return 0;
1169 }
1170
1171 static int
1172 unix_append_message (mailbox_t mbox, message_t msg)
1173 {
1174 unix_data_t mud = mbox->data;
1175 if (msg == NULL || mud == NULL)
1176 return EINVAL;
1177
1178 mailbox_debug (mbox, MU_MAILBOX_DEBUG_TRACE,
1179 "unix_append_message (%s)\n", mbox->name);
1180
1181 unix_lock (mbox, MU_LOCKER_WRLOCK);
1182 {
1183 off_t size;
1184 int status;
1185 size_t n = 0;
1186 char nl = '\n';
1187
1188 /* Move to the end of the file, not necesary if _APPEND mode. */
1189 status = stream_size (mbox->stream, &size);
1190 if (status != 0)
1191 {
1192 unix_unlock (mbox);
1193 return status;
1194 }
1195
1196 switch (mud->state)
1197 {
1198 case UNIX_NO_STATE:
1199 mud->from = calloc (128, sizeof (char));
1200 if (mud->from == NULL)
1201 {
1202 unix_unlock (mbox);
1203 return ENOMEM;
1204 }
1205 mud->date = calloc (128, sizeof (char));
1206 if (mud->date == NULL)
1207 {
1208 free (mud->from);
1209 mud->from = NULL;
1210 mud->state = UNIX_NO_STATE;
1211 unix_unlock (mbox);
1212 return ENOMEM;
1213 }
1214 mud->off = 0;
1215 mud->state = UNIX_STATE_FROM;
1216
1217 case UNIX_STATE_FROM:
1218 /* Generate a "From " separator. */
1219 {
1220 char *s;
1221 size_t len = 0;
1222 status = message_from (msg, mud->from, 127, &len);
1223 if (status != 0)
1224 {
1225 if (status != EAGAIN)
1226 {
1227 free (mud->from);
1228 free (mud->date);
1229 mud->date = mud->from = NULL;
1230 mud->state = UNIX_NO_STATE;
1231 unix_unlock (mbox);
1232 }
1233 return status;
1234 }
1235 /* Nuke trailing newline. */
1236 s = memchr (mud->from, nl, len);
1237 if (s)
1238 *s = '\0';
1239 mud->state = UNIX_STATE_DATE;
1240 }
1241
1242 case UNIX_STATE_DATE:
1243 /* Generate a date for the "From " separator. */
1244 {
1245 char *s;
1246 size_t len = 0;
1247 status = message_received (msg, mud->date, 127, &len);
1248 if (status != 0)
1249 {
1250 if (status != EAGAIN)
1251 {
1252 free (mud->from);
1253 free (mud->date);
1254 mud->date = mud->from = NULL;
1255 mud->state = UNIX_NO_STATE;
1256 unix_unlock (mbox);
1257 }
1258 return status;
1259 }
1260 /* Nuke trailing newline. */
1261 s = memchr (mud->date, nl, len);
1262 if (s)
1263 *s = '\0';
1264 /* Write the separator to the mailbox. */
1265 stream_write (mbox->stream, "From ", 5, size, &n);
1266 size += n;
1267 stream_write (mbox->stream, mud->from, strlen (mud->from), size, &n);
1268 size += n;
1269 stream_write (mbox->stream, " ", 1, size, &n);
1270 size += n;
1271 stream_write (mbox->stream, mud->date, strlen (mud->date), size, &n);
1272 size += n;
1273 stream_write (mbox->stream, &nl , 1, size, &n);
1274 size += n;
1275 free (mud->from);
1276 free (mud->date);
1277 mud->from = mud->date = NULL;
1278 mud->state = UNIX_STATE_APPEND;
1279 }
1280
1281 case UNIX_STATE_APPEND:
1282 /* Append the Message. */
1283 {
1284 char buffer[BUFSIZ];
1285 size_t nread = 0;
1286 stream_t is;
1287 message_get_stream (msg, &is);
1288 do
1289 {
1290 status = stream_read (is, buffer, sizeof (buffer), mud->off,
1291 &nread);
1292 if (status != 0)
1293 {
1294 if (status != EAGAIN)
1295 {
1296 free (mud->from);
1297 free (mud->date);
1298 mud->date = mud->from = NULL;
1299 mud->state = UNIX_NO_STATE;
1300 unix_unlock (mbox);
1301 }
1302 stream_flush (mbox->stream);
1303 return status;
1304 }
1305 stream_write (mbox->stream, buffer, nread, size, &n);
1306 mud->off += nread;
1307 size += n;
1308 }
1309 while (nread > 0);
1310 stream_write (mbox->stream, &nl, 1, size, &n);
1311 }
1312
1313 default:
1314 break;
1315 }
1316 }
1317 stream_flush (mbox->stream);
1318 mud->state = UNIX_NO_STATE;
1319 unix_unlock (mbox);
1320 return 0;
1321 }
1322
1323 static int
1324 unix_size (mailbox_t mbox, off_t *psize)
1325 {
1326 off_t size;
1327 int status;
1328
1329 if (mbox == NULL)
1330 return EINVAL;
1331
1332 /* Maybe was not open yet ?? */
1333 status = stream_size (mbox->stream, &size);
1334 if (status != 0)
1335 return status;
1336 if (psize)
1337 *psize = size;
1338 return 0;
1339 }
1340
1341 static int
1342 unix_messages_count (mailbox_t mbox, size_t *pcount)
1343 {
1344 unix_data_t mud = mbox->data;
1345 if (mud == NULL)
1346 return EINVAL;
1347
1348 if (! unix_is_updated (mbox))
1349 return unix_scan0 (mbox, 1, pcount, 1);
1350
1351 if (pcount)
1352 *pcount = mud->messages_count;
1353
1354 return 0;
1355 }
1356
1357 /* Locking. */
1358 static int
1359 unix_lock (mailbox_t mbox, int flag)
1360 {
1361 if (mbox && mbox->locker != NULL)
1362 {
1363 locker_t locker = mbox->locker;
1364 locker_lock (locker, flag);
1365 }
1366 return 0;
1367 }
1368
1369 static int
1370 unix_touchlock (mailbox_t mbox)
1371 {
1372 if (mbox && mbox->locker != NULL)
1373 {
1374 locker_t locker = mbox->locker;
1375 locker_touchlock (locker);
1376 }
1377 return 0;
1378 }
1379
1380 static int
1381 unix_unlock (mailbox_t mbox)
1382 {
1383 if (mbox && mbox->locker != NULL)
1384 {
1385 locker_t locker = mbox->locker;
1386 locker_unlock (locker);
1387 }
1388 return 0;
1389 }
1390
1391 static int
1392 unix_ilock (mailbox_t mbox, int flag)
1393 {
1394 #ifdef HAVE_PTHREAD_H
1395 (void)flag; /* We should use rwlocks for more concurency. */
1396 if (mbox == NULL)
1397 return EINVAL;
1398 return pthread_mutex_lock (&(mbox->mutex));
1399 #else
1400 (void)mbox; (void)flag;
1401 return 0;
1402 #endif
1403 }
1404
1405 static int
1406 unix_iunlock (mailbox_t mbox)
1407 {
1408 #ifdef HAVE_PTHREAD_H
1409 if (mbox == NULL)
1410 return EINVAL;
1411 return pthread_mutex_unlock (&(mbox->mutex));
1412 #else
1413 (void)mbox;
1414 return 0;
1415 #endif
1416 }
1 /* GNU mailutils - a suite of utilities for electronic mail
2 Copyright (C) 1999, 2000 Free Software Foundation, Inc.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Library Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
17
18 /* Credits to the c-client and its Authors
19 * The notorius c-client VALID() macro, was written by Mark Crispin.
20 */
21
22 /* Parsing.
23 * The approach is to detect the "From " as start of a
24 * new message, give the position of the header and scan
25 * until "\n" then set header_end, set body position,
26 * scan until we it another "From " and set body_end.
27 *
28 ************************************
29 * This is a classic case of premature optimisation
30 * being the root of all Evil(Donald E. Knuth).
31 * But I'm under "pressure" ;-) to come with
32 * something "faster". I think it's wastefull
33 * to spend time to gain a few seconds on 30Megs mailboxes
34 * ... but then again ... in computer time, 60 seconds, is eternity.
35 *
36 * If they use the event notification stuff
37 * to get some headers/messages early ... it's like pissing
38 * in the wind(sorry don't have the english equivalent).
39 * The worst is progress_bar it should be ... &*($^ nuke.
40 * For the events, we have to remove the *.LCK file,
41 * release the locks, flush the stream save the pointers
42 * etc ... hurry and wait...
43 * I this point I'm pretty much ranting.
44 *
45 */
46
47 /* From the C-Client, part of pine */
48 /* You are not expected to understand this macro, but read the next page if
49 * you are not faint of heart.
50 *
51 * Known formats to the VALID macro are:
52 * From user Wed Dec 2 05:53 1992
53 * BSD From user Wed Dec 2 05:53:22 1992
54 * SysV From user Wed Dec 2 05:53 PST 1992
55 * rn From user Wed Dec 2 05:53:22 PST 1992
56 * From user Wed Dec 2 05:53 -0700 1992
57 * From user Wed Dec 2 05:53:22 -0700 1992
58 * From user Wed Dec 2 05:53 1992 PST
59 * From user Wed Dec 2 05:53:22 1992 PST
60 * From user Wed Dec 2 05:53 1992 -0700
61 * Solaris From user Wed Dec 2 05:53:22 1992 -0700
62 *
63 * Plus all of the above with `` remote from xxx'' after it. Thank you very
64 * much, smail and Solaris, for making my life considerably more complicated.
65 */
66 /*
67 * What? You want to understand the VALID macro anyway? Alright, since you
68 * insist. Actually, it isn't really all that difficult, provided that you
69 * take it step by step.
70 *
71 * Line 1 Initializes the return ti value to failure (0);
72 * Lines 2-3 Validates that the 1st-5th characters are ``From ''.
73 * Lines 4-6 Validates that there is an end of line and points x at it.
74 * Lines 7-14 First checks to see if the line is at least 41 characters long
75 .
76 * If so, it scans backwards to find the rightmost space. From
77 * that point, it scans backwards to see if the string matches
78 * `` remote from''. If so, it sets x to point to the space at
79 * the start of the string.
80 * Line 15 Makes sure that there are at least 27 characters in the line.
81 * Lines 16-21 Checks if the date/time ends with the year (there is a space
82 * five characters back). If there is a colon three characters
83 * further back, there is no timezone field, so zn is set to 0
84 * and ti is set in front of the year. Otherwise, there must
85 * either to be a space four characters back for a three-letter
86 * timezone, or a space six characters back followed by a + or -
87 * for a numeric timezone; in either case, zn and ti become the
88 * offset of the space immediately before it.
89 * Lines 22-24 Are the failure case for line 14. If there is a space four
90 * characters back, it is a three-letter timezone; there must be
91 a
92 * space for the year nine characters back. zn is the zone
93 * offset; ti is the offset of the space.
94 * Lines 25-28 Are the failure case for line 20. If there is a space six
95 * characters back, it is a numeric timezone; there must be a
96 * space eleven characters back and a + or - five characters back
97 .
98 * zn is the zone offset; ti is the offset of the space.
99 * Line 29-32 If ti is valid, make sure that the string before ti is of the
100 * form www mmm dd hh:mm or www mmm dd hh:mm:ss, otherwise
101 * invalidate ti. There must be a colon three characters back
102 * and a space six or nine characters back (depending upon
103 * whether or not the character six characters back is a colon).
104 * There must be a space three characters further back (in front
105 * of the day), one seven characters back (in front of the month)
106 ,
107 * and one eleven characters back (in front of the day of week).
108 * ti is set to be the offset of the space before the time.
109 *
110 * Why a macro? It gets invoked a *lot* in a tight loop. On some of the
111 * newer pipelined machines it is faster being open-coded than it would be if
112 * subroutines are called.
113 *
114 * Why does it scan backwards from the end of the line, instead of doing the
115 * much easier forward scan? There is no deterministic way to parse the
116 * ``user'' field, because it may contain unquoted spaces! Yes, I tested it t
117 o
118 * see if unquoted spaces were possible. They are, and I've encountered enoug
119 h
120 * evil mail to be totally unwilling to trust that ``it will never happen''.
121 */
122 #define VALID(s,x,ti,zn) { \
123 ti = 0; \
124 if ((*s == 'F') && (s[1] == 'r') && (s[2] == 'o') && (s[3] == 'm') && \
125 (s[4] == ' ')) { \
126 for (x = s + 5; *x && *x != '\n'; x++); \
127 if (x) { \
128 if (x - s >= 41) { \
129 for (zn = -1; x[zn] != ' '; zn--); \
130 if ((x[zn-1] == 'm') && (x[zn-2] == 'o') && (x[zn-3] == 'r') && \
131 (x[zn-4] == 'f') && (x[zn-5] == ' ') && (x[zn-6] == 'e') && \
132 (x[zn-7] == 't') && (x[zn-8] == 'o') && (x[zn-9] == 'm') && \
133 (x[zn-10] == 'e') && (x[zn-11] == 'r') && (x[zn-12] == ' '))\
134 x += zn - 12; \
135 } \
136 if (x - s >= 27) { \
137 if (x[-5] == ' ') { \
138 if (x[-8] == ':') zn = 0,ti = -5; \
139 else if (x[-9] == ' ') ti = zn = -9; \
140 else if ((x[-11] == ' ') && ((x[-10]=='+') || (x[-10]=='-'))) \
141 ti = zn = -11; \
142 } \
143 else if (x[-4] == ' ') { \
144 if (x[-9] == ' ') zn = -4,ti = -9; \
145 } \
146 else if (x[-6] == ' ') { \
147 if ((x[-11] == ' ') && ((x[-5] == '+') || (x[-5] == '-'))) \
148 zn = -6,ti = -11; \
149 } \
150 if (ti && !((x[ti - 3] == ':') && \
151 (x[ti -= ((x[ti - 6] == ':') ? 9 : 6)] == ' ') && \
152 (x[ti - 3] == ' ') && (x[ti - 7] == ' ') && \
153 (x[ti - 11] == ' '))) ti = 0; \
154 } \
155 } \
156 } \
157 }
158
159 #define STRLEN(s, i) \
160 do \
161 { \
162 char *tmp = (s);\
163 while (*tmp) tmp++; \
164 i = tmp - s; \
165 } while (0)
166
167 #define ATTRIBUTE_SET(buf,mum,c0,c1,type) \
168 do \
169 { \
170 char *s; \
171 for (s = (buf) + 7; *s; s++) \
172 { \
173 if (*s == c0 || *s == c1) \
174 { \
175 (mum)->old_flags |= (type); \
176 break; \
177 } \
178 } \
179 } while (0)
180
181 #define ISSTATUS(buf) (\
182 (buf[0] == 'S' || buf[0] == 's') && \
183 (buf[1] == 'T' || buf[1] == 't') && \
184 (buf[2] == 'A' || buf[2] == 'a') && \
185 (buf[3] == 'T' || buf[3] == 't') && \
186 (buf[4] == 'U' || buf[4] == 'u') && \
187 (buf[5] == 'S' || buf[5] == 's') && (buf[6] == ':'))
188
189 /* Notification. */
190 #define MAILBOX_NOTIFICATION(mbox,which,bailing) \
191 do \
192 { \
193 size_t i; \
194 event_t event; \
195 for (i = 0; i < (mbox)->event_num; i++) \
196 { \
197 event = &((mbox)->event[i]); \
198 if ((event->_action) && (event->type & (which))) \
199 bailing |= event->_action (which, event->arg); \
200 } \
201 } while (0)
202
203 /* Notifications ADD_MESG. */
204 #define DISPATCH_ADD_MSG(mbox,mud) \
205 do \
206 { \
207 int bailing = 0; \
208 unix_iunlock (mbox); \
209 MAILBOX_NOTIFICATION (mbox, MU_EVT_MBX_MSG_ADD, bailing); \
210 if (bailing != 0) \
211 { \
212 if (pcount) \
213 *pcount = (mud)->messages_count; \
214 unix_unlock (mbox); \
215 return EINTR; \
216 } \
217 unix_ilock (mbox, MU_LOCKER_WRLOCK); \
218 } while (0);
219
220 /* Notification MBX_PROGRESS
221 We do not want to fire up the progress notification every line, it will be
222 too expensive, so we do it arbitrarely every 10 000 Lines.
223 FIXME: maybe this should be configurable. */
224 /* This is more tricky we can not leave the mum struct incomplete. So we
225 only tell them about the complete messages. */
226 #define DISPATCH_PROGRESS(mbox,mud) \
227 do \
228 { \
229 { \
230 int bailing = 0; \
231 unix_iunlock (mbox); \
232 mud->messages_count--; \
233 MAILBOX_NOTIFICATION (mbox, MU_EVT_MBX_PROGRESS,bailing); \
234 if (bailing != 0) \
235 { \
236 if (pcount) \
237 *pcount = (mud)->messages_count; \
238 unix_unlock (mbox); \
239 return EINTR; \
240 } \
241 mud->messages_count++; \
242 unix_ilock (mbox, MU_LOCKER_WRLOCK); \
243 } \
244 } while (0)
245
246 /* Allocate slots for the new messages. */
247 /* size_t num = 2 * ((mud)->messages_count) + 10; */
248 #define ALLOCATE_MSGS(mbox,mud) \
249 do \
250 { \
251 if ((mud)->messages_count >= (mud)->umessages_count) \
252 { \
253 unix_message_t *m; \
254 size_t num = ((mud)->umessages_count) + 1; \
255 m = realloc ((mud)->umessages, num * sizeof (*m)); \
256 if (m == NULL) \
257 { \
258 unix_iunlock (mbox); \
259 unix_unlock (mbox); \
260 return ENOMEM; \
261 } \
262 (mud)->umessages = m; \
263 (mud)->umessages[num - 1] = calloc (1, sizeof (*(mum))); \
264 if ((mud)->umessages[num - 1] == NULL) \
265 { \
266 unix_iunlock (mbox); \
267 unix_unlock (mbox); \
268 return ENOMEM; \
269 } \
270 (mud)->umessages_count = num; \
271 } \
272 } while (0)
273
274 static int
275 unix_scan0 (mailbox_t mbox, size_t msgno, size_t *pcount, int do_notif)
276 {
277 #define MSGLINELEN 1024
278 char buf[MSGLINELEN];
279 int inheader;
280 int inbody;
281 off_t total = 0;
282 unix_data_t mud = mbox->data;
283 unix_message_t mum = NULL;
284 int status = 0;
285 size_t lines;
286 int newline;
287 size_t n = 0;
288
289 int zn, isfrom = 0;
290 char *temp;
291
292 /* Sanity. */
293 if (mud == NULL)
294 return EINVAL;
295
296 /* Save the timestamp and size. */
297 status = stream_size (mbox->stream, &(mud->size));
298 if (status != 0)
299 return status;
300
301 /* Grab the locks. */
302 unix_ilock (mbox, MU_LOCKER_WRLOCK);
303 unix_lock (mbox, MU_LOCKER_RDLOCK);
304
305 /* Seek to the starting point. */
306 if (mud->umessages && msgno > 0 && mud->messages_count > 0
307 && msgno <= mud->messages_count)
308 {
309 mum = mud->umessages[msgno - 1];
310 if (mum)
311 total = mum->header_from;
312 mud->messages_count = msgno - 1;
313 }
314 else
315 mud->messages_count = 0;
316
317 newline = 1;
318 errno = lines = inheader = inbody = 0;
319
320 while ((status = stream_readline (mbox->stream, buf, sizeof (buf),
321 total, &n)) == 0 && n != 0)
322 {
323 int nl;
324 total += n;
325
326 nl = (*buf == '\n') ? 1 : 0;
327 VALID(buf, temp, isfrom, zn);
328 isfrom = (isfrom) ? 1 : 0;
329
330 /* Which part of the message are we in ? */
331 inheader = isfrom | ((!nl) & inheader);
332 inbody = (!isfrom) & (!inheader);
333
334 lines++;
335
336 if (inheader)
337 {
338 /* New message. */
339 if (isfrom)
340 {
341 /* Signal the end of the body. */
342 if (mum && !mum->body_end)
343 {
344 mum->body_end = total - n - newline;
345 mum->body_lines = --lines - newline;
346 if (do_notif)
347 DISPATCH_ADD_MSG(mbox, mud);
348 }
349 /* Allocate_msgs will initialize mum. */
350 ALLOCATE_MSGS(mbox, mud);
351 mud->messages_count++;
352 mum = mud->umessages[mud->messages_count - 1];
353 mum->stream = mbox->stream;
354 mum->header_from = total - n;
355 mum->header_from_end = total;
356 lines = 0;
357 }
358 else if ((n > 7) && ISSTATUS(buf))
359 {
360 mum->header_status = total - n;
361 mum->header_status_end = total;
362 ATTRIBUTE_SET(buf, mum, 'r', 'R', MU_ATTRIBUTE_READ);
363 ATTRIBUTE_SET(buf, mum, 'o', 'O', MU_ATTRIBUTE_SEEN);
364 ATTRIBUTE_SET(buf, mum, 'a', 'A', MU_ATTRIBUTE_ANSWERED);
365 ATTRIBUTE_SET(buf, mum, 'd', 'D', MU_ATTRIBUTE_DELETED);
366 }
367 }
368
369 /* Body. */
370 if (inbody)
371 {
372 /* Set the body position. */
373 if (mum && !mum->body)
374 {
375 mum->body = total - n + nl;
376 mum->header_lines = lines;
377 lines = 0;
378 }
379 }
380
381 newline = nl;
382
383 /* Every 50 mesgs update the lock, it should be every minute. */
384 if ((mud->messages_count % 50) == 0)
385 unix_touchlock (mbox);
386
387 /* Ping them every 1000 lines. */
388 if (do_notif)
389 if (((lines +1) % 1000) == 0)
390 DISPATCH_PROGRESS(mbox, mud);
391
392 } /* while */
393
394 if (mum)
395 {
396 mum->body_end = total - newline;
397 mum->body_lines = lines - newline;
398 if (do_notif)
399 DISPATCH_ADD_MSG(mbox, mud);
400 }
401 unix_iunlock (mbox);
402 unix_unlock (mbox);
403 if (pcount)
404 *pcount = mud->messages_count;
405 return status;
406 }
1 /* GNU mailutils - a suite of utilities for electronic mail
2 Copyright (C) 1999, 2000 Free Software Foundation, Inc.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU Library General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
17
18 #include <url0.h>
19 #include <mailutils/registrar.h>
20 #include <errno.h>
21
22 static int url_imap_create (url_t *purl, const char *name);
23 static void url_imap_destroy (url_t *purl);
24
25 struct url_registrar _url_imap_registrar =
26 {
27 "imap://",
28 url_imap_create, url_imap_destroy
29 };
30
31 static void
32 url_imap_destroy (url_t *purl)
33 {
34 (void)purl;
35 return;
36 }
37
38 static int
39 url_imap_create (url_t *purl, const char *name)
40 {
41 (void)purl; (void)name;
42 return ENOSYS;
43 }
1 /* GNU mailutils - a suite of utilities for electronic mail
2 Copyright (C) 1999, 2000 Free Software Foundation, Inc.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU Library General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
17
18 #include <url0.h>
19 #include <mailutils/registrar.h>
20 #include <errno.h>
21
22 static int url_mailto_create (url_t *purl, const char *name);
23 static void url_mailto_destroy (url_t *purl);
24
25 struct url_registrar _url_mailto_registrar =
26 {
27 "mailto:",
28 url_mailto_create, url_mailto_destroy
29 };
30
31 static void
32 url_mailto_destroy (url_t *purl)
33 {
34 (void)purl;
35 return;
36 }
37
38 static int
39 url_mailto_create (url_t *purl, const char *name)
40 {
41 (void)purl; (void)name;
42 return ENOSYS;
43 }
1 /* GNU mailutils - a suite of utilities for electronic mail
2 Copyright (C) 1999, 2000 Free Software Foundation, Inc.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU Library General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
17
18 #include <url0.h>
19 #include <mailutils/registrar.h>
20
21 #include <errno.h>
22 #include <stdlib.h>
23 #include <string.h>
24
25 static void url_maildir_destroy (url_t *purl);
26 static int url_maildir_create (url_t *purl, const char *name);
27
28 struct url_registrar _url_maildir_registrar =
29 {
30 "maildir:",
31 url_maildir_create, url_maildir_destroy
32 };
33
34 static void
35 url_maildir_destroy (url_t *purl)
36 {
37 if (purl && *purl)
38 {
39 url_t url = *purl;
40 free (url->scheme);
41 free (url->path);
42 free (url);
43 *purl = NULL;
44 }
45 }
46
47 /*
48 MAILDIR URL
49 maildir:
50 */
51 static int
52 url_maildir_create (url_t *purl, const char *name)
53 {
54 url_t url;
55 struct url_registrar *ureg = &_url_maildir_registrar;
56 size_t len, scheme_len = strlen (ureg->scheme);
57
58 /* reject the obvious */
59 if (name == NULL || strncmp (ureg->scheme, name, scheme_len) != 0
60 || (len = strlen (name)) < (scheme_len + 1) /* (scheme)+1(path)*/)
61 return EINVAL;
62
63 /* do I need to decode url encoding '% hex hex' ? */
64
65 url = calloc(1, sizeof (*url));
66 if (url == NULL)
67 return EINVAL;
68
69 /* TYPE */
70 url->_create = ureg->_create;
71 url->_destroy = ureg->_destroy;
72
73 /* SCHEME */
74 url->scheme = strdup (ureg->scheme);
75 if (url->scheme == NULL)
76 {
77 ureg->_destroy (&url);
78 return ENOMEM;
79 }
80
81 /* PATH */
82 name += scheme_len; /* pass the scheme */
83 url->path = strdup (name);
84 if (url->path == NULL)
85 {
86 ureg->_destroy (&url);
87 return ENOMEM;
88 }
89
90 *purl = url;
91 return 0;
92 }
1 /* GNU mailutils - a suite of utilities for electronic mail
2 Copyright (C) 1999, 2000 Free Software Foundation, Inc.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU Library General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
17
18 #include <url0.h>
19 #include <mailutils/registrar.h>
20
21 #include <errno.h>
22 #include <stdlib.h>
23 #include <string.h>
24
25 static void url_mh_destroy (url_t *purl);
26 static int url_mh_create (url_t *purl, const char *name);
27
28 struct url_registrar _url_mh_registrar =
29 {
30 "mh:",
31 url_mh_create, url_mh_destroy
32 };
33
34 static void
35 url_mh_destroy (url_t *purl)
36 {
37 if (purl && *purl)
38 {
39 url_t url = *purl;
40 free (url->scheme);
41 free (url->path);
42 free (url);
43 *purl = NULL;
44 }
45 }
46
47 /*
48 MH URL
49 mh:
50 */
51 static int
52 url_mh_create (url_t *purl, const char *name)
53 {
54 url_t url;
55 struct url_registrar *ureg = &_url_mh_registrar;
56 size_t len, scheme_len = strlen (ureg->scheme);
57
58 /* reject the obvious */
59 if (name == NULL || strncmp (ureg->scheme, name, scheme_len) != 0
60 || (len = strlen (name)) < (scheme_len + 1) /* (scheme)+1(path)*/)
61 return EINVAL;
62
63 /* do I need to decode url encoding '% hex hex' ? */
64
65 url = calloc(1, sizeof (*url));
66 if (url == NULL)
67 return ENOMEM;
68
69 /* TYPE */
70 url->_create = ureg->_create;
71 url->_destroy = ureg->_destroy;
72
73 /* SCHEME */
74 url->scheme = strdup (ureg->scheme);
75 if (url->scheme == NULL)
76 {
77 ureg->_destroy (&url);
78 return ENOMEM;
79 }
80
81 /* PATH */
82 name += scheme_len; /* pass the scheme */
83 url->path = strdup (name);
84 if (url->path == NULL)
85 {
86 ureg->_destroy (&url);
87 return ENOMEM;
88 }
89
90 *purl = url;
91 return 0;
92 }
1 /* GNU mailutils - a suite of utilities for electronic mail
2 Copyright (C) 1999, 2000 Free Software Foundation, Inc.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU Library General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
17
18 #include <url0.h>
19 #include <mailutils/registrar.h>
20
21 #include <errno.h>
22 #include <stdlib.h>
23 #include <string.h>
24
25 static void url_mmdf_destroy (url_t *purl);
26 static int url_mmdf_create (url_t *purl, const char *name);
27
28 struct url_registrar _url_mmdf_registrar =
29 {
30 "mmdf:",
31 url_mmdf_create, url_mmdf_destroy
32 };
33
34 static void
35 url_mmdf_destroy (url_t *purl)
36 {
37 if (purl && *purl)
38 {
39 url_t url = *purl;
40 free (url->scheme);
41 free (url->path);
42 free (url);
43 *purl = NULL;
44 }
45 }
46
47 /*
48 MMDF URL
49 mmdf:
50 */
51 static int
52 url_mmdf_create (url_t *purl, const char *name)
53 {
54 url_t url;
55 struct url_registrar *ureg = &_url_mmdf_registrar;
56 size_t len, scheme_len = strlen (ureg->scheme);
57
58 /* reject the obvious */
59 if (name == NULL || strncmp (ureg->scheme, name, scheme_len) != 0
60 || (len = strlen (name)) < 8 /* 7(scheme)+1(path)*/)
61 return EINVAL;
62
63 /* do I need to decode url encoding '% hex hex' ? */
64
65 url = calloc(1, sizeof (*url));
66 if (url == NULL)
67 return ENOMEM;
68
69 /* TYPE */
70 url->_create = ureg->_create;
71 url->_destroy = ureg->_destroy;
72
73 /* SCHEME */
74 url->scheme = strdup (ureg->scheme);
75 if (url->scheme == NULL)
76 {
77 ureg->_destroy (&url);
78 return ENOMEM;
79 }
80
81 /* PATH */
82 name += scheme_len; /* pass the scheme */
83 url->path = strdup (name);
84 if (url->path == NULL)
85 {
86 ureg->_destroy (&url);
87 return ENOMEM;
88 }
89
90 *purl = url;
91 return 0;
92 }
1 /* GNU mailutils - a suite of utilities for electronic mail
2 Copyright (C) 1999, 2000 Free Software Foundation, Inc.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU Library General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
17
18 #include <url0.h>
19 #include <mailutils/registrar.h>
20
21 #include <errno.h>
22 #include <stdlib.h>
23 #include <string.h>
24
25 static void url_unix_destroy (url_t *purl);
26 static int url_unix_create (url_t *purl, const char *name);
27
28 struct url_registrar _url_unix_registrar =
29 {
30 "unix:",
31 url_unix_create, url_unix_destroy
32 };
33
34 static void
35 url_unix_destroy (url_t *purl)
36 {
37 if (purl && *purl)
38 {
39 url_t url = *purl;
40 free (url->scheme);
41 free (url->path);
42 free (url);
43 *purl = NULL;
44 }
45 }
46
47 /*
48 UNIX Mbox
49 unix:/path
50 */
51 static int
52 url_unix_create (url_t *purl, const char *name)
53 {
54 url_t url;
55 struct url_registrar *ureg = &_url_unix_registrar;
56 size_t len, scheme_len = strlen (ureg->scheme);
57
58 /* reject the obvious */
59 if (name == NULL || strncmp (ureg->scheme, name, scheme_len) != 0
60 || (len = strlen (name)) < scheme_len + 1 /* 7(scheme)+1(path)*/)
61 return EINVAL;
62
63 /* do I need to decode url encoding '% hex hex' ? */
64
65 url = calloc(1, sizeof (*url));
66 if (url == NULL)
67 return ENOMEM;
68
69 /* TYPE */
70 url->_create = ureg->_create;
71 url->_destroy = ureg->_destroy;
72
73 /* SCHEME */
74 url->scheme = strdup (ureg->scheme);
75 if (url->scheme == NULL)
76 {
77 ureg->_destroy (&url);
78 return ENOMEM;
79 }
80
81 /* PATH */
82 name += scheme_len; /* pass the scheme */
83 url->path = strdup (name);
84 if (url->path == NULL)
85 {
86 ureg->_destroy (&url);
87 return ENOMEM;
88 }
89
90 *purl = url;
91 return 0;
92 }