~ubuntu-branches/ubuntu/edgy/mew-beta/edgy

« back to all changes in this revision

Viewing changes to bin/incm.c

  • Committer: Bazaar Package Importer
  • Author(s): Tatsuya Kinoshita
  • Date: 2004-06-13 01:11:33 UTC
  • Revision ID: james.westby@ubuntu.com-20040613011133-yaef6kqhoimiq3lx
Tags: upstream-4.0.65
ImportĀ upstreamĀ versionĀ 4.0.65

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  incm - incorporating new mails
 
3
 *
 
4
 *  Author:  Yasunari Momoi <momo@bug.org>
 
5
 *  Created: 2000/10/19
 
6
 */
 
7
 
 
8
#include "mew.h"
 
9
 
 
10
private char version_message[] = "version 4.1 20030217 Yasunari Momoi";
 
11
 
 
12
#include <stdio.h>
 
13
#include <stdlib.h>
 
14
#include <stdarg.h>
 
15
#include <ctype.h>
 
16
#include <string.h>
 
17
#include <sys/stat.h>
 
18
#include <sys/types.h>
 
19
#include <pwd.h>
 
20
#include <signal.h>
 
21
#include <errno.h>
 
22
 
 
23
#if TIME_WITH_SYS_TIME
 
24
# include <sys/time.h>
 
25
# include <time.h>
 
26
#else
 
27
# if HAVE_SYS_TIME_H
 
28
#  include <sys/time.h>
 
29
# else
 
30
#  include <time.h>
 
31
# endif
 
32
#endif
 
33
 
 
34
#if HAVE_DIRENT_H
 
35
# include <dirent.h>
 
36
#endif
 
37
 
 
38
#if HAVE_FCNTL_H
 
39
# include <fcntl.h>
 
40
#endif
 
41
 
 
42
#if HAVE_SYS_FILE_H
 
43
# include <sys/file.h>
 
44
#endif
 
45
 
 
46
#if HAVE_UNISTD_H
 
47
# include <unistd.h>
 
48
#endif
 
49
 
 
50
enum MBOXTYPE {
 
51
    T_UNKNOWN,
 
52
    T_MAILDIR,
 
53
    T_MBOX,
 
54
    T_STDIN,
 
55
};
 
56
 
 
57
enum MBOXSTATE {
 
58
    ST_UNKNOWN,
 
59
    ST_HEADER,
 
60
    ST_BODY_AFTER_EMPTY_LINE,
 
61
    ST_BODY,
 
62
};
 
63
 
 
64
#define FBUFSIZ         (BUFSIZ * 32)
 
65
#ifndef PATH_MAX
 
66
# define PATH_MAX       1024
 
67
#endif
 
68
 
 
69
private char    FileBuf[FBUFSIZ];
 
70
private char    InboxDir[PATH_MAX];
 
71
private char    Mbox[PATH_MAX];
 
72
private char    MboxLock[PATH_MAX];
 
73
private int     MboxType;
 
74
private int     Backup;
 
75
private int     GetCur;
 
76
private int     UseCL;
 
77
private int     CreateMTime = TRUE;
 
78
private int     Exit = 0;
 
79
 
 
80
/****************************************************************
 
81
 *
 
82
 * prototype
 
83
 *
 
84
 */
 
85
 
 
86
private void    error(const char *, ...);
 
87
private void    usage(const char *);
 
88
private void    help(const char *);
 
89
private void    version(const char *);
 
90
private void    init_env(int, char **);
 
91
private int     is_number(unsigned char *);
 
92
private int     get_last_seq(void);
 
93
private int     compare_string(char **, char **);
 
94
private void    copyfile(char *, char *);
 
95
private void    movefile(char *, char *, char *, int);
 
96
private int     maildir_names(const char *, char **, char **, char **);
 
97
private int     new_inbox_file(int, char[]);
 
98
private FILE    *open_new_inbox_file(int *, char[]);
 
99
private int     get_from_dir(int, char *, char *, int);
 
100
private int     process_maildir(int);
 
101
private int     lock_mbox(char *);
 
102
private void    unlock_mbox(char *);
 
103
private int     process_mbox(int);
 
104
private int     process_stdin(int);
 
105
private void    process(void);
 
106
private int     check_mbox_type(const char *);
 
107
private void    sanity_check(void);
 
108
 
 
109
 
 
110
#if !HAVE_FLOCK
 
111
# if HAVE_LOCKF
 
112
#  define flock(a, b)   lockf(a, b, 0)
 
113
#  define LOCK_EX       F_LOCK
 
114
# endif
 
115
#endif
 
116
 
 
117
#ifndef S_ISDIR
 
118
# define S_ISDIR(m)     (((m) & S_IFMT) == S_IFDIR)
 
119
#endif
 
120
#ifndef S_ISREG
 
121
# define S_ISREG(m)     (((m) & S_IFMT) == S_IFREG)
 
122
#endif
 
123
 
 
124
private char *
 
125
Getlogin(void)
 
126
{
 
127
#ifdef HAVE_GETLOGIN
 
128
        {
 
129
                char *user;
 
130
                if ((user = getlogin()) != NULL)
 
131
                        return user;
 
132
        }
 
133
#endif
 
134
#ifdef HAVE_GETPWUID
 
135
        {
 
136
                struct passwd *pw;
 
137
                if ((pw = getpwuid(getuid())) == NULL)
 
138
                        return NULL;
 
139
                else
 
140
                        return pw->pw_name;
 
141
        }
 
142
#endif
 
143
        return NULL;
 
144
}
 
145
 
 
146
private char *
 
147
Gethomedir(void)
 
148
{
 
149
        char *home;
 
150
 
 
151
        if ((home = getenv("HOME")) != NULL)
 
152
                return home;
 
153
#ifdef HAVE_GETPWUID
 
154
        {
 
155
                struct passwd *pw;
 
156
                if ((pw = getpwuid(getuid())) == NULL)
 
157
                        return NULL;
 
158
                else
 
159
                        return pw->pw_dir;
 
160
        }
 
161
#endif
 
162
        return NULL;
 
163
}
 
164
 
 
165
#if !HAVE_STRDUP
 
166
private char *
 
167
strdup(const char *str)
 
168
{
 
169
        char* t;
 
170
        MALLOC(t, strlen(str) + 1);
 
171
        if (t)
 
172
                strcpy(t, str);
 
173
        return t;
 
174
}
 
175
#endif
 
176
 
 
177
private void
 
178
error(const char *fmt, ...)
 
179
{
 
180
        va_list ap;
 
181
        if (warn_prog != NULL)
 
182
                fprintf(stderr, "%s: ", warn_prog);
 
183
        va_start(ap, fmt);
 
184
        if (fmt != NULL)
 
185
                vfprintf(stderr, fmt, ap);
 
186
        va_end(ap);
 
187
        fprintf(stderr, "\n");
 
188
        if (strlen(MboxLock) > 0)
 
189
                unlock_mbox(MboxLock);
 
190
        exit(EXIT_FAILURE);
 
191
}
 
192
 
 
193
/****************************************************************
 
194
 * 
 
195
 * options and usages
 
196
 *
 
197
 */
 
198
 
 
199
 
 
200
#define LOCK_SUFFIX     ".lock"
 
201
#define MAILDIR         "Maildir"
 
202
#define MAILDIR_NEW     "new"
 
203
#define MAILDIR_CUR     "cur"
 
204
#define MAILDIR_TMP     "tmp"
 
205
 
 
206
private void
 
207
usage(const char *progname) {
 
208
        fprintf(stderr, "Usage: %s [-abchsv] [-d maildir] [-i inboxdir]\n", progname);
 
209
}
 
210
 
 
211
private const char *
 
212
help_message[] = {
 
213
        "    -h            Display this help message.",
 
214
        "    -v            Display the version.",
 
215
        "    -d <mail>     Path to mbox/maildir.",
 
216
        "    -m <mail>     Path to mbox/maildir.",
 
217
        "    -s            Read one mail from stdin instead of mbox/maildir.",
 
218
        "    -i <inboxdir> Path to inboxdir.",
 
219
        "    -b            Backup mail.",
 
220
        "                    mbox: No truncate mbox file.",
 
221
        "                    maildir: To maildir/cur directory.",
 
222
        "    -a            Retrieve all mail from maildir/{cur,new} directory.",
 
223
        "                  (no backup) (for maildir)",
 
224
        "    -c            Use Content-Length: field. (for mbox)",
 
225
        "    -u            Don't create inboxdir/.mew-mtime file.",
 
226
        NULL
 
227
};
 
228
 
 
229
private void
 
230
help(const char *progname) {
 
231
        const char **p = help_message;
 
232
 
 
233
        fprintf(stderr, "Help: %s\n\n", progname);
 
234
        fprintf(stderr, " Incorporating new mails.\n\n");
 
235
        usage(progname);
 
236
        while (*p) fprintf(stderr, "%s\n", *p++);
 
237
}
 
238
 
 
239
private void
 
240
version(const char *progname) {
 
241
        fprintf(stderr, "%s %s\n", progname, version_message);
 
242
}
 
243
 
 
244
private int
 
245
check_mbox_type(const char *path)
 
246
{
 
247
        struct stat sb;
 
248
 
 
249
        if (stat(path, &sb))
 
250
                return T_UNKNOWN;
 
251
        if (S_ISDIR(sb.st_mode)) {
 
252
                char* newdir;
 
253
                char* curdir;
 
254
 
 
255
                if (maildir_names(path, &newdir, &curdir, NULL))
 
256
                        error("maildir name is not set (%s)", path);
 
257
                if (stat(newdir, &sb))
 
258
                        return T_UNKNOWN;
 
259
                if (!S_ISDIR(sb.st_mode) || access(newdir, R_OK|W_OK|X_OK))
 
260
                        return T_UNKNOWN;
 
261
 
 
262
                if (Backup) {
 
263
                        if (stat(curdir, &sb))
 
264
                                return T_UNKNOWN;
 
265
                        if (!S_ISDIR(sb.st_mode) || access(curdir, W_OK))
 
266
                                return T_UNKNOWN;
 
267
                }
 
268
                return T_MAILDIR;
 
269
        }
 
270
        else if (S_ISREG(sb.st_mode))
 
271
                return T_MBOX;
 
272
        else
 
273
                return T_UNKNOWN;
 
274
}
 
275
 
 
276
private const char *
 
277
mbox_path_list[] = {
 
278
        "/var/mail/",
 
279
        "/var/spool/mail/",
 
280
        "/usr/spool/mail/",
 
281
        NULL
 
282
};
 
283
 
 
284
private void
 
285
search_mbox_path(void)
 
286
{
 
287
        char *home, *mail, *user;
 
288
 
 
289
        if ((home = Gethomedir()) != NULL) {
 
290
                if (strlen(home) + 9 > PATH_MAX)
 
291
                        error("pathname too long (%s)", home);
 
292
                sprintf(Mbox, "%s/%s", home, MAILDIR);
 
293
                if (check_mbox_type(Mbox) != T_UNKNOWN)
 
294
                        return;
 
295
        }
 
296
        if ((mail = getenv("MAIL")) != NULL) {
 
297
                if (strlen(mail) + 1 > PATH_MAX)
 
298
                        error("pathname too long (%s)", mail);
 
299
                sprintf(Mbox, mail);
 
300
                if (check_mbox_type(Mbox) != T_UNKNOWN)
 
301
                        return;
 
302
        }
 
303
        if ((user = Getlogin()) != NULL) {
 
304
                int i;
 
305
                for (i = 0; mbox_path_list[i] != NULL; i++) {
 
306
                        if (strlen(mbox_path_list[i]) + strlen(user) + 1
 
307
                            > PATH_MAX)
 
308
                                error("pathname too long (%s)", user);
 
309
                        sprintf(Mbox, "%s%s", mbox_path_list[i], user);
 
310
                        if (check_mbox_type(Mbox) != T_UNKNOWN)
 
311
                                return;
 
312
                }
 
313
        }
 
314
        sprintf(Mbox, ".");
 
315
        return;
 
316
}
 
317
 
 
318
void
 
319
sig_exit(int signo)
 
320
{
 
321
        Exit = 1;
 
322
}
 
323
 
 
324
void
 
325
sig_ignore(int signo)
 
326
{
 
327
        /* ignore signal */
 
328
}
 
329
 
 
330
private void
 
331
set_sighandler(void)
 
332
{
 
333
        if (signal(SIGHUP, sig_ignore) == SIG_ERR)
 
334
                error("can't catch SIGHUP\n");
 
335
        if (signal(SIGINT, sig_exit) == SIG_ERR)
 
336
                error("can't catch SIGINT\n");
 
337
        if (signal(SIGALRM, sig_ignore) == SIG_ERR)
 
338
                error("can't catch SIGALRM\n");
 
339
        if (signal(SIGTERM, sig_ignore) == SIG_ERR)
 
340
                error("can't catch SIGTERM\n");
 
341
}
 
342
 
 
343
private void
 
344
init_env(int argc, char **argv)
 
345
{
 
346
        set_sighandler();
 
347
        sprintf(InboxDir, ".");
 
348
        MboxType = T_UNKNOWN;
 
349
        Backup = FALSE;
 
350
        UseCL = FALSE;
 
351
        search_mbox_path();
 
352
}
 
353
 
 
354
private int
 
355
is_number(unsigned char *str)
 
356
{
 
357
        do {
 
358
                if (!isdigit(*str))
 
359
                        return FALSE;
 
360
        } while (*++str != '\0');
 
361
        return TRUE;
 
362
}
 
363
 
 
364
private int
 
365
get_last_seq(void)
 
366
{
 
367
        struct dirent *dp;
 
368
        DIR *dirp;
 
369
        int last = 0;
 
370
        int seq;
 
371
 
 
372
        if ((dirp = opendir(InboxDir)) == NULL)
 
373
                error("opendir(%s)", InboxDir);
 
374
        while ((dp = readdir(dirp)) != NULL) {
 
375
                if (!is_number(dp->d_name))
 
376
                        continue;
 
377
                seq = atoi(dp->d_name);
 
378
                last = last > seq ? last : seq;
 
379
        }
 
380
        closedir(dirp);
 
381
        return last;
 
382
}
 
383
 
 
384
private int
 
385
compare_string(char **i, char **j)
 
386
{
 
387
        return strcmp(*i, *j);
 
388
}
 
389
 
 
390
private void
 
391
copyfile(char *src, char *dst)
 
392
{
 
393
        struct timeval tv[2];
 
394
        struct stat sb;
 
395
        int srcfd, dstfd;
 
396
        ssize_t rlen, wlen;
 
397
 
 
398
        if ((srcfd = open(src, O_RDONLY, 0)) < 0)
 
399
                error("open(%s) for read", src);
 
400
        if (fstat(srcfd, &sb))
 
401
                error("fstat(%s)", src);
 
402
        if ((dstfd = open(dst, O_EXCL | O_CREAT | O_WRONLY | O_TRUNC, 0)) < 0)
 
403
                error("open(%s) for write", dst);
 
404
        while ((rlen = read(srcfd, FileBuf, FBUFSIZ)) > 0) {
 
405
                if ((wlen = write(dstfd, FileBuf, rlen)) != rlen) {
 
406
                        close(dstfd);
 
407
                        unlink(dst);
 
408
                        error("write(%s) (read %d bytes/write %d bytes)",
 
409
                              dst, rlen, wlen);
 
410
                }
 
411
        }
 
412
        if (rlen < 0) {
 
413
                close(dstfd);
 
414
                unlink(dst);
 
415
                error("read(%s)", src);
 
416
        }
 
417
        close(srcfd);
 
418
 
 
419
        tv[0].tv_sec = sb.st_atime;
 
420
        tv[0].tv_usec = 0;
 
421
        tv[1].tv_sec = sb.st_mtime;
 
422
        tv[1].tv_usec = 0;
 
423
#if HAVE_FUTIMES
 
424
        if (futimes(dstfd, tv))
 
425
                warning("futimes(%s) failed", dst);
 
426
#endif
 
427
#if HAVE_FCHMOD
 
428
        if (fchmod(dstfd, sb.st_mode))
 
429
                warning("fchmod(%s) failed", dst);
 
430
#endif
 
431
        close(dstfd);
 
432
#if !HAVE_FUTIMES
 
433
        if (utimes(dst, tv))
 
434
                warning("utimes(%s) failed", dst);
 
435
#endif
 
436
#if !HAVE_FCHMOD
 
437
        if (chmod(dst, sb.st_mode))
 
438
                warning("chmod(%s) failed", dst);
 
439
#endif
 
440
}
 
441
 
 
442
private void
 
443
movefile(char *fromfile, char *tofile, char *backupfile, int backup)
 
444
{
 
445
        if (backup && backupfile != NULL) {
 
446
                copyfile(fromfile, tofile);
 
447
                if (rename(fromfile, backupfile))
 
448
                        error("rename(%s, %s)", fromfile, backupfile);
 
449
        }
 
450
        else if (backup) {
 
451
                copyfile(fromfile, tofile);
 
452
        }
 
453
        else {
 
454
                if (rename(fromfile, tofile)) {
 
455
                        if (errno != EXDEV)
 
456
                                error("rename(%s, %s)", fromfile, tofile);
 
457
                        copyfile(fromfile, tofile);
 
458
                        if (unlink(fromfile))
 
459
                                error("unlink(%s)", fromfile);
 
460
                }
 
461
        }
 
462
}
 
463
 
 
464
/* maildir has {new,cur,tmp} subdirectory. */
 
465
private int
 
466
maildir_names(const char *maildir, char **newdir, char **curdir, char **tmpdir)
 
467
{
 
468
        int len = strlen(maildir) + strlen(MAILDIR_NEW) + 2;
 
469
 
 
470
        if (maildir == NULL || strlen(maildir) <= 0)
 
471
                return -1;
 
472
        if (newdir != NULL) {
 
473
                MALLOC(*newdir, len);
 
474
                sprintf(*newdir, "%s/%s", maildir, MAILDIR_NEW);
 
475
        }
 
476
        if (curdir != NULL) {
 
477
                MALLOC(*curdir, len);
 
478
                sprintf(*curdir, "%s/%s", maildir, MAILDIR_CUR);
 
479
        }
 
480
        if (tmpdir != NULL) {
 
481
                MALLOC(*tmpdir, len);
 
482
                sprintf(*tmpdir, "%s/%s", maildir, MAILDIR_TMP);
 
483
        }
 
484
        return 0;
 
485
}
 
486
 
 
487
/* *WARNING* inboxfile requires PATH_MAX bytes */
 
488
private int
 
489
new_inbox_file(int seq, char inboxfile[])
 
490
{
 
491
        char num[PATH_MAX];
 
492
        do {
 
493
                sprintf(num, "%d", ++seq);
 
494
                if (strlen(InboxDir) + strlen(num) + 2 > PATH_MAX)
 
495
                        error("pathname too long (%s/%s)", InboxDir, num);
 
496
                sprintf(inboxfile, "%s/%s", InboxDir, num);
 
497
                if (access(inboxfile, F_OK) && errno == ENOENT)
 
498
                        break;
 
499
        } while (TRUE);
 
500
        return seq;
 
501
}
 
502
 
 
503
/* *WARNING* inboxfile requires PATH_MAX bytes */
 
504
private FILE *
 
505
open_new_inbox_file(int *seq, char inboxfile[]) 
 
506
{
 
507
        char num[PATH_MAX];
 
508
        int flag = O_EXCL | O_CREAT | O_WRONLY;
 
509
        int mode = S_IRUSR | S_IRGRP | S_IROTH |
 
510
                   S_IWUSR | S_IWGRP | S_IWOTH;
 
511
        int fd;
 
512
        FILE *fp = NULL;
 
513
 
 
514
        for (;;) {
 
515
                sprintf(num, "%d", ++*seq);
 
516
                if (strlen(InboxDir) + strlen(num) + 2 > PATH_MAX)
 
517
                        error("pathname too long (%s/%s)", InboxDir, num);
 
518
                sprintf(inboxfile, "%s/%s", InboxDir, num);
 
519
                if ((fd = open(inboxfile, flag, mode)) >= 0 ||
 
520
                    errno != EEXIST)
 
521
                        break;
 
522
                usleep(rand() % 199);
 
523
        }
 
524
        if (fd < 0)
 
525
                warning("open(%s) for write", inboxfile);
 
526
        else {
 
527
                if ((fp = fdopen(fd, FDWRITE)) == NULL)
 
528
                        warning("open(%s) for write", inboxfile);
 
529
        }
 
530
        return fp;
 
531
}
 
532
 
 
533
private int
 
534
get_from_dir(int seq, char *fromdir, char *backupdir, int backup)
 
535
{
 
536
        struct stat sb;
 
537
        struct dirent *dp;
 
538
        DIR *dirp;
 
539
        char mailfile[PATH_MAX];
 
540
        char inboxfile[PATH_MAX];
 
541
        char backupfile[PATH_MAX];
 
542
        char **list;
 
543
        int listsize = BUFSIZ;
 
544
        int listend = 0;
 
545
        int i;
 
546
 
 
547
        MALLOC(list, sizeof(char *)*listsize);
 
548
        if ((dirp = opendir(fromdir)) == NULL)
 
549
                error("opendir(%s)", fromdir);
 
550
        while ((dp = readdir(dirp)) != NULL) {
 
551
                if (strlen(fromdir) + strlen(dp->d_name) + 2 > PATH_MAX)
 
552
                        error("pathname too long (%s/%s)",
 
553
                              fromdir, dp->d_name);
 
554
                sprintf(mailfile, "%s/%s", fromdir, dp->d_name);
 
555
                if (stat(mailfile, &sb))
 
556
                        continue;
 
557
                if (!(S_ISREG(sb.st_mode) && (sb.st_mode & S_IRUSR)))
 
558
                        continue;
 
559
                if (listend >= listsize) {
 
560
                        listsize *= 2;
 
561
                        if ((list = (char **)
 
562
                             realloc(list, sizeof(char *)*listsize)) == NULL)
 
563
                                error("realloc");
 
564
                }
 
565
                if ((list[listend++] = strdup(dp->d_name)) == NULL)
 
566
                        error("strdup(%s)", dp->d_name);
 
567
        }
 
568
        closedir(dirp);
 
569
 
 
570
        qsort(list, listend, sizeof(char *),
 
571
              (int (*)(const void *, const void *))compare_string);
 
572
 
 
573
        for (i = 0; i < listend; i++) {
 
574
                seq = new_inbox_file(seq, inboxfile);
 
575
                if (strlen(fromdir) + strlen(list[i]) + 2 > PATH_MAX)
 
576
                        error("pathname too long (%s/%s)",
 
577
                              fromdir, list[i]);
 
578
                sprintf(mailfile, "%s/%s", fromdir, list[i]);
 
579
                if (backup && backupdir != NULL) {
 
580
                        if (strlen(backupdir) + strlen(list[i]) + 6 > PATH_MAX)
 
581
                                error("pathname too long (%s/%s)",
 
582
                                      backupdir, list[i]);
 
583
                        sprintf(backupfile, "%s/%s:2,S", backupdir, list[i]);
 
584
                        movefile(mailfile, inboxfile, backupfile, backup);
 
585
                }
 
586
                else
 
587
                        movefile(mailfile, inboxfile, NULL, backup);
 
588
                printf("%d\n", seq);
 
589
        }
 
590
        return seq;
 
591
}
 
592
 
 
593
private int
 
594
process_maildir(int seq)
 
595
{
 
596
        char *newdir, *curdir;
 
597
        if (maildir_names(Mbox, &newdir, &curdir, NULL))
 
598
                error("maildir name is not set (%s)", Mbox);
 
599
        if (GetCur)
 
600
                seq = get_from_dir(seq, curdir, NULL, Backup);
 
601
        return get_from_dir(seq, newdir, curdir, Backup);
 
602
}
 
603
 
 
604
private int
 
605
lock_mbox(char *lockfile)
 
606
{
 
607
        int fd;
 
608
        int retry = 5;
 
609
 
 
610
        while (TRUE) {
 
611
                if ((fd = open(lockfile, O_WRONLY | O_CREAT | O_EXCL)) < 0) {
 
612
                        if (errno == EACCES || errno == EROFS)
 
613
                                return 1; /* doesn't need a lockfile, maybe. */
 
614
                        else if (errno != EEXIST)
 
615
                                error("open(%s)", lockfile);
 
616
                        if (retry-- <= 0)
 
617
                                error("can't get lock(%s)", lockfile);
 
618
                }
 
619
                else {
 
620
                        /* lock succeeded. */
 
621
                        write(fd, "0", 1);
 
622
                        close(fd);
 
623
                        return 0;
 
624
                }
 
625
                sleep(2);
 
626
        }
 
627
}
 
628
 
 
629
private void
 
630
unlock_mbox(char *lockfile)
 
631
{
 
632
        if (strlen(lockfile) > 0)
 
633
                unlink(lockfile);
 
634
}
 
635
 
 
636
private int
 
637
process_mbox(int seq)
 
638
{
 
639
        char inboxfile[PATH_MAX];
 
640
        char emptyline[3];
 
641
        char *ln;
 
642
        int srcfd, oflag;
 
643
        FILE *srcfp = NULL;
 
644
        FILE *dstfp = NULL;
 
645
        int state = ST_UNKNOWN;
 
646
        int bytes = -1;         /* UseCL (Content-Length:) */
 
647
 
 
648
        if (strlen(Mbox) + strlen(LOCK_SUFFIX) + 1 > PATH_MAX)
 
649
                error("pathname too long (%s%s)", Mbox, LOCK_SUFFIX);
 
650
        sprintf(MboxLock, "%s%s", Mbox, LOCK_SUFFIX);
 
651
        if (lock_mbox(MboxLock))
 
652
                MboxLock[0] = '\0'; /* doesn't need a lockfile, maybe. */
 
653
 
 
654
        oflag = O_RDWR;
 
655
#if defined(O_EXLOCK)
 
656
        oflag |= O_EXLOCK;
 
657
#endif
 
658
        if ((srcfd = open(Mbox, oflag, 0)) < 0) {
 
659
                warning("open(%s) for rw/truncate", Mbox);  goto rerr;
 
660
        }
 
661
#if !defined(O_EXLOCK) && (HAVE_FLOCK || HAVE_LOCKF)
 
662
        if (flock(srcfd, LOCK_EX) < 0) {
 
663
                warning("flock(%s)", Mbox);  goto rerr;
 
664
        }
 
665
#endif
 
666
        if ((srcfp = fdopen(srcfd, FDREAD)) == NULL) {
 
667
                warning("fdopen(%s) for read", Mbox);  goto rerr;
 
668
        }
 
669
 
 
670
        while ((ln = getline(srcfp)) != NULL) {
 
671
                if (Exit)
 
672
                        goto werr;
 
673
                switch (state) {
 
674
                case ST_UNKNOWN:
 
675
                        if (strncmp(ln, "From ", 5) == 0) {
 
676
                                dstfp = open_new_inbox_file(&seq, inboxfile);
 
677
                                if (dstfp == NULL)
 
678
                                        goto rerr;
 
679
                                state = ST_HEADER;
 
680
                        }
 
681
                        break;
 
682
                case ST_HEADER:
 
683
                        if (strlen(ln) < 3 &&
 
684
                            (ln[0] == '\n' || ln[0] == '\r')) {
 
685
                                strcpy(emptyline, ln);
 
686
                                state = ST_BODY_AFTER_EMPTY_LINE;
 
687
                                break;
 
688
                        }
 
689
                        if (fputs(ln, dstfp) == EOF) {
 
690
                                warning("fputs(%s)", inboxfile);  goto werr;
 
691
                        }
 
692
                        if (UseCL &&
 
693
                            strncasecmp(ln, "Content-Length", 14) == 0) {
 
694
                                int i;
 
695
                                for (i = 14; i < strlen(ln); i++)
 
696
                                        if (isdigit((unsigned char)ln[i]))
 
697
                                                break;
 
698
                                bytes = atoi(&ln[i]);
 
699
                        }
 
700
                        break;
 
701
                case ST_BODY_AFTER_EMPTY_LINE:
 
702
                        if (bytes < 0 && strncmp(ln, "From ", 5) == 0) {
 
703
                                fclose(dstfp);
 
704
                                printf("%d\n", seq);
 
705
 
 
706
                                dstfp = open_new_inbox_file(&seq, inboxfile);
 
707
                                if (dstfp == NULL)
 
708
                                        goto rerr;
 
709
                                state = ST_HEADER;
 
710
                                break;
 
711
                        }
 
712
                        else if (fputs(emptyline, dstfp) == EOF)
 
713
                                goto werr;
 
714
                        /* FALLTHRU */
 
715
                case ST_BODY:
 
716
                        if (strlen(ln) < 3 &&
 
717
                            (ln[0] == '\n' || ln[0] == '\r')) {
 
718
                                strcpy(emptyline, ln);
 
719
                                state = ST_BODY_AFTER_EMPTY_LINE;
 
720
                        }
 
721
                        else
 
722
                                state = ST_BODY;
 
723
 
 
724
                        if (state == ST_BODY && fputs(ln, dstfp) == EOF)
 
725
                                goto werr;
 
726
                        if (bytes >= 0) {
 
727
                                bytes -= strlen(ln);
 
728
                                if (bytes <= 0) {
 
729
                                        fclose(dstfp);  dstfp = NULL;
 
730
                                        printf("%d\n", seq);
 
731
                                        state = ST_UNKNOWN;
 
732
                                        bytes = -1;
 
733
                                        break;
 
734
                                }
 
735
                        }
 
736
                        break;
 
737
                }
 
738
                free(ln);
 
739
        }
 
740
        if (dstfp) {
 
741
                fclose(dstfp);
 
742
                printf("%d\n", seq);
 
743
        }
 
744
        if (!Backup && ftruncate(srcfd, 0)) {
 
745
                unlock_mbox(MboxLock);
 
746
                error("ftruncate");
 
747
        }
 
748
        fclose(srcfp);
 
749
        unlock_mbox(MboxLock);
 
750
        return seq;
 
751
 
 
752
 werr:
 
753
        if (dstfp)
 
754
                fclose(dstfp);
 
755
        unlink(inboxfile);
 
756
 rerr:
 
757
        if (srcfp)
 
758
                fclose(srcfp);
 
759
        unlock_mbox(MboxLock);
 
760
        error("process_mbox(%s)", Mbox);
 
761
        return -1;              /* error. not reached */
 
762
}
 
763
 
 
764
private int
 
765
process_stdin(int seq)
 
766
{
 
767
        char inboxfile[PATH_MAX];
 
768
        char *ln;
 
769
        FILE *srcfp = stdin;
 
770
        FILE *dstfp;
 
771
 
 
772
        if ((dstfp = open_new_inbox_file(&seq, inboxfile)) == NULL)
 
773
                goto rerr;
 
774
 
 
775
        while ((ln = getline(srcfp)) != NULL) {
 
776
                if (Exit)
 
777
                        goto werr;
 
778
                if (fputs(ln, dstfp) == EOF) {
 
779
                        warning("fputs(%s)", inboxfile);  goto werr;
 
780
                }
 
781
                free(ln);
 
782
        }
 
783
 
 
784
        if (dstfp) {
 
785
                fclose(dstfp);
 
786
                printf("%d\n", seq);
 
787
        }
 
788
        return seq;
 
789
 
 
790
 werr:
 
791
        if (dstfp)
 
792
                fclose(dstfp);
 
793
        unlink(inboxfile);
 
794
 rerr:
 
795
        error("process_stdin");
 
796
        return -1;              /* error. not reached */
 
797
}
 
798
 
 
799
private void
 
800
process(void)
 
801
{
 
802
        char mtimefile[PATH_MAX];
 
803
        FILE *fp;
 
804
        size_t wb;
 
805
        int len = strlen(MEW_MTIME_PHRASE);
 
806
        int seq = get_last_seq();
 
807
        int newseq = 0;
 
808
 
 
809
        switch (MboxType) {
 
810
        case T_MAILDIR:
 
811
                newseq = process_maildir(seq);
 
812
                break;
 
813
        case T_MBOX:
 
814
                newseq = process_mbox(seq);
 
815
                break;
 
816
        case T_STDIN:
 
817
                newseq = process_stdin(seq);
 
818
                break;
 
819
        default:
 
820
                error("unknown mbox type (%s)", Mbox);
 
821
        }
 
822
 
 
823
        /* update .mew-mtime file if new mail arrived */
 
824
        if (!CreateMTime || newseq <= seq)
 
825
                return;         /* no new mail */
 
826
        if (strlen(InboxDir) + strlen(MEW_MTIME_FILE) + 1 > PATH_MAX)
 
827
                error("pathname too long (%s%s)", InboxDir, MEW_MTIME_FILE);
 
828
        sprintf(mtimefile, "%s/%s", InboxDir, MEW_MTIME_FILE);
 
829
 
 
830
        if ((fp = fopen(mtimefile, FDWRITE)) == NULL)
 
831
                error("can't create file (%s)", mtimefile);
 
832
        if ((wb = fwrite(MEW_MTIME_PHRASE, sizeof(char), len, fp)) != len) {
 
833
                fclose(fp);
 
834
                error("fwrite failed (%d, %s)", wb, mtimefile);
 
835
        }
 
836
        fclose(fp);
 
837
}
 
838
 
 
839
private void
 
840
sanity_check(void)
 
841
{
 
842
        struct stat sb;
 
843
 
 
844
        /* was directory exists? */
 
845
        if (stat(InboxDir, &sb))
 
846
                error("stat(%s)", InboxDir);
 
847
        if (!S_ISDIR(sb.st_mode) || access(InboxDir, W_OK))
 
848
                error("can't write directory (%s)", InboxDir);
 
849
 
 
850
        /* mbox type checking */
 
851
        if (MboxType == T_UNKNOWN &&
 
852
            (MboxType = check_mbox_type(Mbox)) == T_UNKNOWN)
 
853
                error("can't find mbox (%s)", Mbox);
 
854
}
 
855
 
 
856
int
 
857
main(int argc, char **argv)
 
858
{
 
859
        extern char *Optarg;
 
860
        extern int Optind;
 
861
        char *progname = getprognm(argv[0]);
 
862
        int ch;
 
863
 
 
864
        warn_prog = progname;
 
865
        init_env(argc, argv);
 
866
 
 
867
        while ((ch = Getopt(argc, argv, "abcd:hi:m:suvp")) != EOF) {
 
868
                switch (ch) {
 
869
                case 'a':
 
870
                        GetCur = TRUE;
 
871
                        break;
 
872
                case 'b':
 
873
                        Backup = TRUE;
 
874
                        break;
 
875
                case 'c':
 
876
                        UseCL = TRUE;
 
877
                        break;
 
878
                case 'd':
 
879
                case 'm':
 
880
                        if (strlen(Optarg) + 1 > PATH_MAX)
 
881
                                error("pathname too long (%s)", Optarg);
 
882
                        sprintf(Mbox, "%s", Optarg);
 
883
                        break;
 
884
                case 'i':
 
885
                        if (strlen(Optarg) + 1 > PATH_MAX)
 
886
                                error("pathname too long (%s)", Optarg);
 
887
                        sprintf(InboxDir, "%s", Optarg);
 
888
                        break;
 
889
                case 'p':       /* for debug */
 
890
                        printf("InboxDir: %s\n", InboxDir);
 
891
                        printf("Mbox: %s\n", Mbox);
 
892
                        exit(EXIT_SUCCESS);
 
893
                case 's':
 
894
                        MboxType = T_STDIN;
 
895
                        break;
 
896
                case 'u':
 
897
                        CreateMTime = FALSE;
 
898
                        break;
 
899
                case 'v':
 
900
                        version(progname);
 
901
                        exit(EXIT_SUCCESS);
 
902
                case 'h':
 
903
                        help(progname);
 
904
                        exit(EXIT_SUCCESS);
 
905
                default:
 
906
                        usage(progname);
 
907
                        exit(EXIT_SUCCESS);
 
908
                }
 
909
        }
 
910
        argc -= Optind;
 
911
        argv += Optind;
 
912
 
 
913
        sanity_check();
 
914
        process();
 
915
        return EXIT_SUCCESS;
 
916
}
 
917
 
 
918
/* 
 
919
 * Copyright (C) 2001-2003 Mew developing team.
 
920
 * All rights reserved.
 
921
 * 
 
922
 * Redistribution and use in source and binary forms, with or without
 
923
 * modification, are permitted provided that the following conditions
 
924
 * are met:
 
925
 * 
 
926
 * 1. Redistributions of source code must retain the above copyright
 
927
 *    notice, this list of conditions and the following disclaimer.
 
928
 * 2. Redistributions in binary form must reproduce the above copyright
 
929
 *    notice, this list of conditions and the following disclaimer in the
 
930
 *    documentation and/or other materials provided with the distribution.
 
931
 * 3. Neither the name of the team nor the names of its contributors
 
932
 *    may be used to endorse or promote products derived from this software
 
933
 *    without specific prior written permission.
 
934
 * 
 
935
 * THIS SOFTWARE IS PROVIDED BY THE TEAM AND CONTRIBUTORS ``AS IS'' AND
 
936
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 
937
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 
938
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE TEAM OR CONTRIBUTORS BE
 
939
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 
940
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 
941
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 
942
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 
943
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 
944
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 
945
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
946
 */
 
947
 
 
948
/*
 
949
 * incm.c ends here
 
950
 */