Ticket #282: omindex-assorted-enhancements.patch

File omindex-assorted-enhancements.patch, 14.0 kB (added by olly, 6 months ago)

Patch updated for SVN HEAD

  • omindex.cc

     
    44 * Copyright 2001,2005 James Aylett 
    55 * Copyright 2001,2002 Ananova Ltd 
    66 * Copyright 2002,2003,2004,2005,2006,2007,2008 Olly Betts 
     7 * Copyright 2006 AVL List GesmbH 
    78 * 
    89 * This program is free software; you can redistribute it and/or 
    910 * modify it under the terms of the GNU General Public License as 
     
    4243#include <xapian.h> 
    4344 
    4445#include "commonhelp.h" 
     46#include "configfile.h" 
    4547#include "diritor.h" 
    4648#include "hashterm.h" 
    4749#include "loadfile.h" 
     
    7274 
    7375static bool skip_duplicates = false; 
    7476static bool follow_symlinks = false; 
     77static bool ignore_time = false; 
     78static bool nocleanup = false; 
    7579static string dbpath; 
    7680static string root; 
    7781static string indexroot; 
    7882static string baseurl; 
     83static string error_log; 
    7984static Xapian::WritableDatabase db; 
    8085static Xapian::Stem stemmer("english"); 
    8186static Xapian::TermGenerator indexer; 
     
    111116    return safefile; 
    112117} 
    113118 
     119inline string 
     120run_cmd(const string & cmd) 
     121{ 
     122    return stdout_to_string(cmd + error_log); 
     123} 
     124 
    114125static bool ensure_tmpdir() { 
    115126    if (!tmpdir.empty()) return true; 
    116127 
     
    140151get_pdf_metainfo(const string & safefile, string &title, string &keywords) 
    141152{ 
    142153    try { 
    143         string pdfinfo = stdout_to_string("pdfinfo -enc UTF-8 " + safefile); 
     154        string pdfinfo = run_cmd("pdfinfo -enc UTF-8 " + safefile); 
    144155 
    145156        string::size_type idx; 
    146157 
     
    195206    if (urlterm.length() > MAX_SAFE_TERM_LENGTH) 
    196207        urlterm = hash_long_term(urlterm, MAX_SAFE_TERM_LENGTH); 
    197208 
    198     if (skip_duplicates && db.term_exists(urlterm)) { 
    199         cout << "duplicate. Ignored." << endl; 
    200         return; 
     209    { 
     210        // First find the docid with the urlterm. 
     211        Xapian::docid docid = 0; 
     212        Xapian::PostingIterator p = db.postlist_begin(urlterm); 
     213        if (p != db.postlist_end(urlterm)) { 
     214            docid = *p; 
     215            if (skip_duplicates) { 
     216                cout << "duplicate. Ignored." << endl; 
     217                return; 
     218            } 
     219        } 
     220        if (docid && !ignore_time) { 
     221            // Check the timestamp. 
     222            Xapian::Document doc = db.get_document(docid); 
     223            string value = doc.get_value(VALUE_LASTMOD); 
     224            time_t old_last_mod = binary_string_to_int(value); 
     225            if (old_last_mod >= last_mod) { 
     226                cout << "not newer. Ignored." << endl; 
     227                return; 
     228            } 
     229        } 
    201230    } 
    202231 
    203232    string md5; 
     
    253282        string safefile = shell_protect(file); 
    254283        string cmd = "pdftotext -enc UTF-8 " + safefile + " -"; 
    255284        try { 
    256             dump = stdout_to_string(cmd); 
     285            dump = run_cmd(cmd); 
    257286        } catch (ReadError) { 
    258287            cout << "\"" << cmd << "\" failed - skipping\n"; 
    259288            return; 
     
    276305        string safetmp = shell_protect(tmpfile); 
    277306        string cmd = "ps2pdf " + shell_protect(file) + " " + safetmp; 
    278307        try { 
    279             (void)stdout_to_string(cmd); 
     308            (void)run_cmd(cmd); 
    280309            cmd = "pdftotext -enc UTF-8 " + safetmp + " -"; 
    281             dump = stdout_to_string(cmd); 
     310            dump = run_cmd(cmd); 
    282311        } catch (ReadError) { 
    283312            cout << "\"" << cmd << "\" failed - skipping" << endl; 
    284313            unlink(tmpfile.c_str()); 
     
    302331        string cmd = "unzip -p " + safefile + " content.xml"; 
    303332        try { 
    304333            XmlParser xmlparser; 
    305             xmlparser.parse_html(stdout_to_string(cmd)); 
     334            xmlparser.parse_html(run_cmd(cmd)); 
    306335            dump = xmlparser.dump; 
    307336        } catch (ReadError) { 
    308337            cout << "\"" << cmd << "\" failed - skipping\n"; 
     
    312341        cmd = "unzip -p " + safefile + " meta.xml"; 
    313342        try { 
    314343            MetaXmlParser metaxmlparser; 
    315             metaxmlparser.parse_html(stdout_to_string(cmd)); 
     344            metaxmlparser.parse_html(run_cmd(cmd)); 
    316345            title = metaxmlparser.title; 
    317346            keywords = metaxmlparser.keywords; 
    318347            sample = metaxmlparser.sample; 
     
    322351    } else if (mimetype == "application/msword") { 
    323352        string cmd = "antiword -mUTF-8.txt " + shell_protect(file); 
    324353        try { 
    325             dump = stdout_to_string(cmd); 
     354            dump = run_cmd(cmd); 
    326355        } catch (ReadError) { 
    327356            cout << "\"" << cmd << "\" failed - skipping\n"; 
    328357            return; 
     
    330359    } else if (mimetype == "application/vnd.ms-excel") { 
    331360        string cmd = "xls2csv -q0 -dutf-8 " + shell_protect(file); 
    332361        try { 
    333             dump = stdout_to_string(cmd); 
     362            dump = run_cmd(cmd); 
    334363        } catch (ReadError) { 
    335364            cout << "\"" << cmd << "\" failed - skipping\n"; 
    336365            return; 
     
    338367    } else if (mimetype == "application/vnd.ms-powerpoint") { 
    339368        string cmd = "catppt -dutf-8 " + shell_protect(file); 
    340369        try { 
    341             dump = stdout_to_string(cmd); 
     370            dump = run_cmd(cmd); 
    342371        } catch (ReadError) { 
    343372            cout << "\"" << cmd << "\" failed - skipping\n"; 
    344373            return; 
     
    349378        // as they don't seem to be at all well documented. 
    350379        string cmd = "wpd2text " + shell_protect(file); 
    351380        try { 
    352             dump = stdout_to_string(cmd); 
     381            dump = run_cmd(cmd); 
    353382        } catch (ReadError) { 
    354383            cout << "\"" << cmd << "\" failed - skipping\n"; 
    355384            return; 
     
    358387        // wps2text produces UTF-8 output from the sample files I've tested. 
    359388        string cmd = "wps2text " + shell_protect(file); 
    360389        try { 
    361             dump = stdout_to_string(cmd); 
     390            dump = run_cmd(cmd); 
    362391        } catch (ReadError) { 
    363392            cout << "\"" << cmd << "\" failed - skipping\n"; 
    364393            return; 
     
    380409        string cmd = "gzip -dc " + shell_protect(file); 
    381410        try { 
    382411            XmlParser xmlparser; 
    383             xmlparser.parse_html(stdout_to_string(cmd)); 
     412            xmlparser.parse_html(run_cmd(cmd)); 
    384413            dump = xmlparser.dump; 
    385414        } catch (ReadError) { 
    386415            cout << "\"" << cmd << "\" failed - skipping\n"; 
     
    389418    } else if (mimetype == "text/rtf") { 
    390419        // The --text option unhelpfully converts all non-ASCII characters to 
    391420        // "?" so we use --html instead, which produces HTML entities. 
    392         string cmd = "unrtf --nopict --html 2>/dev/null " + shell_protect(file); 
     421        string cmd = "unrtf --nopict --html " + shell_protect(file); 
    393422        MyHtmlParser p; 
    394423        try { 
    395             p.parse_html(stdout_to_string(cmd)); 
     424            p.parse_html(run_cmd(cmd)); 
    396425        } catch (ReadError) { 
    397426            cout << "\"" << cmd << "\" failed - skipping\n"; 
    398427            return; 
     
    413442        // from inspecting the source it looks like it's probably iso-8859-1. 
    414443        string cmd = "pod2text " + shell_protect(file); 
    415444        try { 
    416             dump = stdout_to_string(cmd); 
     445            dump = run_cmd(cmd); 
    417446            convert_to_utf8(dump, "ISO-8859-1"); 
    418447        } catch (ReadError) { 
    419448            cout << "\"" << cmd << "\" failed - skipping\n"; 
     
    427456        // decompositions". 
    428457        string cmd = "catdvi -e2 -s " + shell_protect(file); 
    429458        try { 
    430             dump = stdout_to_string(cmd); 
     459            dump = run_cmd(cmd); 
    431460            convert_to_utf8(dump, "ISO-8859-1"); 
    432461        } catch (ReadError) { 
    433462            cout << "\"" << cmd << "\" failed - skipping\n"; 
     
    440469        // (as it is in CP1250). 
    441470        string cmd = "djvutxt " + shell_protect(file); 
    442471        try { 
    443             dump = stdout_to_string(cmd); 
     472            dump = run_cmd(cmd); 
    444473        } catch (ReadError) { 
    445474            cout << "\"" << cmd << "\" failed - skipping\n"; 
    446475            return; 
    447476        } 
     477#if 0 // FIXME: this won't work as omindex will have the database locked... 
     478    } else if (mimetype == "message/rfc822") { 
     479        // => mbox2script 
     480        //for stemmer lang, parse stemmer.get_description => Xapian::Stem(bla) 
     481        string cmd = "(mbox2omega " + shell_protect(file) + "|" 
     482            "scriptindex " + shell_protect(dbpath) + " /usr/share/omega/mbox2script.script)"; 
     483        try { 
     484            dump = run_cmd(cmd); 
     485        } catch (ReadError) { 
     486            cout << "\"" << cmd << "\" failed - skipping\n"; 
     487            return; 
     488        } 
     489#endif 
     490    } else if (mimetype == "application/vnd.ms-outlook") { // msg 
     491        string cmd = "outlook2text " + shell_protect(file); 
     492        try { 
     493            dump = run_cmd(cmd); 
     494        } catch (ReadError) { 
     495            cout << "\"" << cmd << "\" failed - skipping\n"; 
     496            return; 
     497        } 
    448498    } else { 
    449499        // Don't know how to index this type. 
    450500        cout << "unknown MIME type - skipping\n"; 
     
    581631                    } 
    582632                    continue; 
    583633                case DirectoryIterator::REGULAR_FILE: { 
     634                    if (strcmp(d.leafname(), "mbox") == 0) { 
     635                        // Special filename. 
     636                        off_t size = d.get_size(); 
     637                        time_t mtime = d.get_mtime(); 
     638                        index_file(indexroot + url, "message/rfc822", mtime, 
     639                                   size); 
     640                        continue; 
     641                    } 
     642 
    584643                    string ext; 
    585644                    string::size_type dot = url.find_last_of('.'); 
    586645                    if (dot != string::npos) ext = url.substr(dot + 1); 
     
    613672 
    614673                        // It's in our MIME map so we know how to index it. 
    615674                        const string & mimetype = mt->second; 
     675 
     676                        // NOTE: unpacking does not work on MSWin32 this way! 
     677                        // We'd really have to pull in utils.cc:rmdir from 
     678                        // xapian-core. 
     679#ifndef _MSC_VER 
     680                        if (ext == "rar") { 
     681                            // TODO: Check timestamp 
     682                            string x = root+indexroot+"/.rar"; 
     683                            cout << "[UNRAR into " << shell_protect(x+url) << "]" << endl; 
     684                            run_cmd("mkdir -p "+shell_protect(x+url)); 
     685                            string cmd = "unrar x -o+ " +shell_protect(file) + " " + shell_protect(x+url+"/"); 
     686                            run_cmd(cmd); 
     687                            index_directory(5, "/.rar"+url, mime_map); 
     688                            if (!nocleanup) { 
     689                                cout << "[CLEANUP " << "rm -rf " << shell_protect(x) << "]" << endl; 
     690                                run_cmd("rm -rf "+shell_protect(x)); 
     691                            } 
     692                        } else if (ext == "zip") { 
     693                            // TODO: Check timestamp 
     694                            string x = root+indexroot+"/.zip"; 
     695                            cout << "[UNZIP into " << shell_protect(x+url) << "]" << endl; 
     696                            run_cmd("mkdir -p "+shell_protect(x+url)); 
     697                            string cmd = "unzip -o " +shell_protect(file) + " -d " +shell_protect(x+url+"/"); 
     698                            run_cmd(cmd); 
     699                            index_directory(5, "/.zip"+url, mime_map); 
     700                            if (!nocleanup) { 
     701                                cout << "[CLEANUP " << "rm -rf " << shell_protect(x) << "]" << endl; 
     702                                run_cmd("rm -rf "+shell_protect(x)); 
     703                            } 
     704                        } else if (ext == "pst") { 
     705                            // TODO: Check timestamp 
     706                            string x = root+indexroot+"/.pst"; 
     707                            cout << "[READPST into " << shell_protect(x+url) << "]" << endl; 
     708                            run_cmd("mkdir -p "+shell_protect(x+url)); 
     709                            // unpack attachments also, together with mbox files 
     710                            string cmd = "readpst -r -cv -w -o "+shell_protect(x+url)+" "+shell_protect(file); 
     711                            run_cmd(cmd); 
     712                            cout << "[UNPACK mbox attachments in " << shell_protect(x+url) << "]" << endl; 
     713                            cmd = "/usr/bin/find "+shell_protect(x+url)+" -name mbox -execdir uudeview -a -o -i '{}' ';'"; 
     714                            run_cmd(cmd); 
     715                            index_directory(5, "/.pst"+url, mime_map); // mbox handling 
     716                            if (!nocleanup) { 
     717                                cout << "[CLEANUP " << "rm -rf " << shell_protect(x) << "]" << endl; 
     718                                run_cmd("rm -rf "+shell_protect(x)); 
     719                            } 
     720                        } else 
     721#endif 
    616722                        try { 
    617723                            time_t mtime = d.get_mtime(); 
    618724                            index_file(indexroot + url, mimetype, mtime, size); 
     
    653759    // If preserve_unupdated is false, delete any documents we don't 
    654760    // replace (if in replace duplicates mode) 
    655761    bool preserve_unupdated = false; 
     762    // If ignore_time is true, the existing timestamps are not checked on 
     763    // updates and every file will be parsed. 
    656764    size_t depth_limit = 0; 
    657765 
    658766    static const struct option longopts[] = { 
     
    667775        { "depth-limit",required_argument,      NULL, 'l' }, 
    668776        { "follow",     no_argument,            NULL, 'f' }, 
    669777        { "stemmer",    required_argument,      NULL, 's' }, 
     778        { "ignore-time",no_argument,            NULL, 'i' }, 
     779        { "nocleanup",  no_argument,            NULL, 'c' }, 
    670780        { 0, 0, NULL, 0 } 
    671781    }; 
    672782 
     
    742852    mime_map["djv"] = "image/vnd.djvu"; 
    743853    mime_map["djvu"] = "image/vnd.djvu"; 
    744854 
    745     while ((getopt_ret = gnu_getopt_long(argc, argv, "hvd:D:U:M:lpf", longopts, NULL)) != -1) { 
     855    mime_map["msg"] = "application/vnd.ms-outlook";     // outlook2text - single message 
     856    mime_map["pst"] = "application/vnd.ms-outlook-pst"; // readpst | mimeexpand (libpst, Mime-tools) Outlook messager folder 
     857    mime_map["mbox"] = "message/rfc822";                // => mbox2script 
     858 
     859#ifndef _MSC_VER 
     860    mime_map["zip"] = "application/x-zip"; // recursive scanning 
     861    mime_map["rar"] = "application/x-rar"; // recursive scanning 
     862#endif 
     863 
     864    read_config_file(); 
     865 
     866    while ((getopt_ret = gnu_getopt_long(argc, argv, "hvd:D:U:M:lpfi", longopts, NULL)) != -1) { 
    746867        switch (getopt_ret) { 
    747868        case 'h': { 
    748869            cout << PROG_NAME" - "PROG_DESC"\n\n" 
     
    756877"  -M, --mime-type          additional MIME mapping ext:type\n" 
    757878"  -l, --depth-limit=LIMIT  set recursion limit (0 = unlimited)\n" 
    758879"  -f, --follow             follow symbolic links\n" 
     880"  -i, --ignore-time        ignore timestamp comparison\n" 
     881"      --nocleanup          don't delete temporary created from zip/rar/pst\n" 
    759882"      --overwrite          create the database anew (the default is to update\n" 
    760883"                           if the database already exists)" << endl; 
    761884            print_stemmer_help("     "); 
     
    769892                 << "Copyright (c) 2001,2005 James Aylett\n" 
    770893                 << "Copyright (c) 2001,2002 Ananova Ltd\n" 
    771894                 << "Copyright (c) 2002,2003,2004,2005,2006 Olly Betts\n\n" 
     895                 << "Copyright (c) 2006 AVL List GesmbH\n\n" 
    772896                 << "This is free software, and may be redistributed under\n" 
    773897                 << "the terms of the GNU Public License." << endl; 
    774898            return 0; 
     
    785909        case 'p': // don't delete unupdated documents 
    786910            preserve_unupdated = true; 
    787911            break; 
     912        case 'i': // --ignore-time: on updates parse the file again 
     913            ignore_time = true; 
     914            break; 
     915        case 'c': 
     916            nocleanup = true; 
     917            break; 
    788918        case 'l': { // Set recursion limit 
    789919            int arg = atoi(optarg); 
    790920            if (arg < 0) arg = 0; 
     
    844974    if (baseurl.empty()) { 
    845975        cerr << PROG_NAME": --url not specified, assuming `/'.\n"; 
    846976    } 
     977    error_log = " 2>>"+log_dir+"omindex-error.log"; 
    847978    // baseurl mustn't end '/' or you end up with the wrong URL 
    848979    // (//thing is different to /thing). We could probably make this 
    849980    // safe a different way, by ensuring that we don't put a leading '/' 
  • Makefile.am

     
    103103omindex_SOURCES = omindex.cc myhtmlparse.cc htmlparse.cc\ 
    104104 common/getopt.cc commonhelp.cc utils.cc hashterm.cc loadfile.cc md5.cc\ 
    105105 md5wrap.cc xmlparse.cc metaxmlparse.cc utf8convert.cc sample.cc diritor.cc\ 
    106  runfilter.cc freemem.cc common/msvc_dirent.cc 
     106 runfilter.cc freemem.cc common/msvc_dirent.cc configfile.cc 
    107107if NEED_MKDTEMP 
    108108omindex_SOURCES += portability/mkdtemp.cc 
    109109endif