~ubuntu-branches/ubuntu/raring/lurker/raring

« back to all changes in this revision

Viewing changes to index/main.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jonas Meurer
  • Date: 2006-12-20 05:05:31 UTC
  • mfrom: (3.1.6 feisty)
  • Revision ID: james.westby@ubuntu.com-20061220050531-79inzy7o6uu95qx7
Tags: 2.1-7
* updated vi debconf translations, thanks to Clytie Siddall
  <clytie@riverland.net.au>
* fixed typo in one template (that you would like, not that
  would you like), thanks as well to Clytie Siddall
  - unfuzzied all translations

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*  $Id: main.cpp,v 1.42 2004/08/25 21:39:46 terpstra Exp $
 
1
/*  $Id: main.cpp,v 1.49 2006/03/01 14:11:05 terpstra Exp $
2
2
 *  
3
3
 *  main.cpp - Read the fed data into our database
4
4
 *  
22
22
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23
23
 */
24
24
 
25
 
#define _XOPEN_SOURCE 500
26
25
#define _FILE_OFFSET_BITS 64
27
26
 
28
27
#include <mimelib/headers.h>
35
34
#include <esort.h>
36
35
 
37
36
#include <iostream>
 
37
#include <set>
38
38
#include <cstdio>
39
39
#include <ctime>
40
40
#include <cstdlib>
44
44
#include <fcntl.h>
45
45
#include <unistd.h>
46
46
#include <dirent.h>
 
47
#include <errno.h>
47
48
 
48
49
#include <zlib.h>
49
50
 
50
51
#include "Index.h"
 
52
#include <XmlEscape.h>
 
53
#include <Keys.h>
 
54
 
 
55
#include "config.h"
 
56
#ifdef HAVE_SYSEXITS_H
 
57
#include <sysexits.h>
 
58
#define LEX_USAGE       EX_USAGE
 
59
#define LEX_IOERR       EX_IOERR
 
60
#define LEX_DATAERR     EX_DATAERR
 
61
#else
 
62
#define LEX_USAGE       1
 
63
#define LEX_IOERR       2
 
64
#define LEX_DATAERR     3
 
65
#endif
51
66
 
52
67
// Our friendly neighbourhood date parser (getdate.y / getdate.cpp)
53
68
time_t get_date (const char *p, const time_t *now);
55
70
using namespace std;
56
71
 
57
72
auto_ptr<ESort::Writer> db;
 
73
set<MessageId> blacklist;
58
74
 
59
75
string         append;
60
76
List*          list = 0;
65
81
long messagecount = 0;
66
82
off_t processedbytes = 0;
67
83
 
68
 
long batch = 0;
 
84
const long batch = 10;
 
85
bool ismbox = true;
69
86
bool verbose = false;
70
87
bool dropdup = false;
71
88
bool synced = true;
76
93
{
77
94
        cerr << "Lurker-index (v" << VERSION << ") imports messages into the archive.\n";
78
95
        cerr << "\n";
79
 
        cerr << "Usage: " << name << " -c <config-file> -l <list> (-m | -b <count>)\n";
80
 
        cerr << "                                     [-i <mbox/maildir> -v -d -n -u -f]\n";
 
96
        cerr << "Usage: " << name << " -l <list> [-c <config-file>]\n";
 
97
        cerr << "                                     [-m -i <mbox/maildir> -v -d -n -u -f]\n";
81
98
        cerr << "\n";
 
99
        cerr << "\t-l <list>        Import messages to the named list\n";
82
100
        cerr << "\t-c <config-file> Use this config file for lurker settings\n";
83
 
        cerr << "\t-l <list>        Import messages to the named list\n";
84
 
        cerr << "\t-b <count>       Import a batch of messages; flush every count messages\n";
 
101
        cerr << "\t-m               Input is a single message (not a mailbox)\n";
85
102
        cerr << "\t-i <mbox/mdir>   Read input from mbox or maildir instead of std input\n";
86
 
        cerr << "\t-m               Import a single message\n";
 
103
        cerr << "\t-p <history>     Prevent deleted messages in DB history from importing\n";
87
104
        cerr << "\t-v               Verbose operation\n";
88
105
        cerr << "\t-d               Drop duplicates per list\n";
89
106
        cerr << "\t-n               Don't compress messages\n";
90
107
        cerr << "\t-u               Trust the user Date header more than arrival time\n";
91
108
        cerr << "\t-f               Fast import (but vulnerable to power-failure)\n";
92
109
        cerr << "\n";
93
 
        cerr << "Index messages from standard input and store them in the lurker database.\n";
94
 
        cerr << "Either import a single message, or import a batch of messages in mbox format.\n";
 
110
        cerr << "Index messages and store them in the lurker database.\n";
95
111
        cerr << "\n";
96
112
}
97
113
 
341
357
                append.append(msg.c_str(), msg.length());
342
358
        }
343
359
        
344
 
        Index i(message, db.get(), *list, start, msg.length() + strlen(prefix));
 
360
        Index i(message, db.get(), *list, blacklist, 
 
361
                start, msg.length() + strlen(prefix));
345
362
        
346
363
        bool exist;
347
364
        if (i.index(userdate, arrival, import, dropdup, exist) != 0)
428
445
                // well, we gave it the benefit of the doubt, but ...
429
446
                // this just don't look like a message break
430
447
                
431
 
                cerr << "warning: treating '" << header << "' as part of a message because it does not have an @ in the username or a valid date." << endl;
 
448
                cerr << "warning: treating '" << xmlEscape << header << "' (string is xml escaped) as part of a message because it does not have an @ in the username or a valid date." << endl;
432
449
                // implicitly continue the loop
433
450
        }
434
451
        
456
473
                
457
474
                string::size_type eos;
458
475
                /* Look for message boundaries only if:
459
 
                 *  We are importing a batch of messsages
460
 
                 *  We are NOT importing a file from a maildir
 
476
                 *  We are importing from an mbox (not single, not maildir)
461
477
                 */
462
 
                while (batch != -1 && arrival == 0 &&
 
478
                while (ismbox && 
463
479
                       (eos = find_message_boundary(buf, was)) != string::npos)
464
480
                {
465
481
                        DwString msg(buf.c_str(), eos);
478
494
                if (got == 0)
479
495
                {
480
496
                        /* Don't index the empty string!
481
 
                         * If single maildir file or raw delivery or message.
 
497
                         * If not an mbox, or has leading mbox text
482
498
                         */
483
 
                        if (buf.length() && 
484
 
                            (batch == -1 || arrival != 0 || buf[0] == 'F'))
 
499
                        if (buf.length() && (!ismbox || buf[0] == 'F'))
485
500
                        {
486
501
                                DwString msg(buf.c_str(), buf.length());
487
502
                                buf = "";
531
546
{
532
547
        int c;
533
548
        
534
 
        const char* config  = 0;
 
549
        const char* config  = DEFAULT_CONFIG_FILE;
535
550
        const char* listn   = 0;
536
551
        const char* input   = 0;
 
552
        const char* histdb  = 0;
 
553
        bool single = false;
537
554
        
538
555
        srandom(time(0));
539
556
        
540
 
        while ((c = getopt(argc, (char*const*)argv, "c:l:b:i:mvndfu?")) != -1)
 
557
        while ((c = getopt(argc, (char*const*)argv, "c:l:i:p:mvndfu?")) != -1)
541
558
        {
542
559
                switch ((char)c)
543
560
                {
547
564
                case 'l':
548
565
                        listn = optarg;
549
566
                        break;
550
 
                case 'b':
551
 
                        batch = atol(optarg);
552
 
                        break;
553
567
                case 'i':
554
568
                        input = optarg;
555
569
                        break;
 
570
                case 'p':
 
571
                        histdb = optarg;
 
572
                        break;
556
573
                case 'm':
557
 
                        batch = -1;
 
574
                        single = true;
558
575
                        break;
559
576
                case 'v':
560
577
                        verbose = true;
573
590
                        break;
574
591
                default:
575
592
                        help(argv[0]);
576
 
                        return 1;
577
 
                }
578
 
        }
579
 
        
580
 
        if (!config || !listn || batch == 0 || optind < argc)
581
 
        {
582
 
                help(argv[0]);
583
 
                return 1;
 
593
                        return LEX_USAGE;
 
594
                }
 
595
        }
 
596
        
 
597
        while (optind < argc)
 
598
        {
 
599
                if (!argv[optind][0])
 
600
                {       // ignore empty arguments
 
601
                        optind++;
 
602
                        continue;
 
603
                }
 
604
                
 
605
                cerr << "Unexpected argument: '" << argv[optind] << "'\n";
 
606
                return LEX_USAGE;
 
607
        }
 
608
        
 
609
        if (!listn)
 
610
        {
 
611
                cerr << "No list was specified (the -l option is manditory)\n";
 
612
                return LEX_USAGE;
584
613
        }
585
614
        
586
615
        Config cfg;
587
616
        if (cfg.load(config) != 0)
588
617
        {
589
618
                cerr << cfg.getError() << flush;
590
 
                return 1;
 
619
                return LEX_DATAERR;
591
620
        }
592
621
        
593
622
        Config::Lists::iterator i = cfg.lists.find(listn);
594
623
        if (i == cfg.lists.end())
595
624
        {
596
625
                cerr << "No such list '" << listn << "' defined; cannot import to it." << endl;
597
 
                return 1;
 
626
                return LEX_DATAERR;
598
627
        }
599
628
        list = &i->second;
600
629
        
601
630
        if (list->offline)
602
631
        {
603
632
                cerr << "The list '" << listn << "' is marked as offline; cannot import to it." << endl;
604
 
                return 1;
 
633
                return LEX_DATAERR;
605
634
        }
606
635
        
 
636
        string dbname = cfg.dbdir + "/db";
607
637
        ESort::Parameters params(synced);
608
638
        // work around g++ 2.95 borkage
609
639
        auto_ptr<ESort::Writer> dbt(
610
 
                ESort::Writer::opendb(cfg.dbdir + "/db", params));
 
640
                ESort::Writer::opendb(dbname, params));
611
641
        db = dbt;
612
642
        
613
643
        if (!db.get())
614
644
        {
615
 
                perror("opening database");
616
 
                return 1;
 
645
                perror(dbname.c_str());
 
646
                return LEX_IOERR;
617
647
        }
618
648
        
619
649
        string mboxf = cfg.dbdir + "/" + listn;
621
651
        if (mbox == -1)
622
652
        {
623
653
                perror(mboxf.c_str());
624
 
                return 1;
 
654
                return LEX_IOERR;
625
655
        }
626
656
        length = lseek(mbox, 0, SEEK_END);
627
657
        
 
658
        /* load the blacklist from the old database */
 
659
        if (histdb)
 
660
        {
 
661
                auto_ptr<ESort::Reader> dbh(
 
662
                        ESort::Reader::opendb(histdb, params));
 
663
                if (!dbh.get())
 
664
                {
 
665
                        perror(histdb);
 
666
                        return LEX_IOERR;
 
667
                }
 
668
                
 
669
                string prefix(LU_KEYWORD + string(LU_KEYWORD_DELETED) + '\0');
 
670
                auto_ptr<ESort::Walker> walk(
 
671
                        dbh->seek(prefix, "", ESort::Forward));
 
672
                
 
673
                while (walk->advance() != -1)
 
674
                {
 
675
                        if (walk->key.length() != 
 
676
                            prefix.length() + MessageId::raw_len)
 
677
                        {
 
678
                                cerr << histdb << " contains corrupt deleted entries" << endl;
 
679
                                return LEX_IOERR;
 
680
                        }
 
681
                        
 
682
                        MessageId id(walk->key.c_str() + prefix.length(), 
 
683
                                     MessageId::raw_len);
 
684
                        blacklist.insert(id);
 
685
                }
 
686
                if (errno != 0)
 
687
                {
 
688
                        perror("walking history database");
 
689
                        return LEX_IOERR;
 
690
                }
 
691
        }
 
692
        
628
693
        /** Begin processing input.
629
694
         */
630
695
        
634
699
                DIR* d = opendir((string(input) + "/new").c_str());
635
700
                if (d)
636
701
                {
 
702
                        ismbox = false; /* maildirs don't have mboxes */
637
703
                        if (maildir(d, 
638
704
                                string(input) + "/new",
639
705
                                string(input) + "/cur") != 0)
640
 
                                return 1;
 
706
                                return LEX_IOERR;
641
707
                        closedir(d);
642
708
                }
643
709
                else
644
710
                {
 
711
                        ismbox = !single;
645
712
                        FILE* f = fopen(input, "rb");
646
713
                        if (!f)
647
714
                        {
648
715
                                perror(input);
649
716
                                cerr << "Opening input file failed!" << endl;
650
 
                                return 1;
 
717
                                return LEX_IOERR;
651
718
                        }
652
719
                        if (process_mail(f, 0) != 0)
653
 
                                return 1;
 
720
                                return LEX_IOERR;
654
721
                        fclose(f);
655
722
                }
656
723
        }
657
724
        else
658
725
        {
659
 
                if (process_mail(stdin, 0) != 0) return 1;
 
726
                ismbox = !single;
 
727
                if (process_mail(stdin, 0) != 0) return LEX_IOERR;
660
728
        }
661
729
        
662
 
        if (commit() != 0) return 1;
 
730
        if (commit() != 0) return LEX_IOERR;
663
731
        if (verbose) status();
664
732
        
665
733
        return 0;