home *** CD-ROM | disk | FTP | other *** search
/ PC Online 1999 November / PCONLINE_11_99.ISO / filesbbs / OS2 / MMSRC029.ZIP / mmail-0.29 / mmail / resource.cc < prev    next >
Encoding:
C/C++ Source or Header  |  1999-08-22  |  11.6 KB  |  490 lines

  1. /*
  2.  * MultiMail offline mail reader
  3.  * resource class
  4.  
  5.  Copyright (c) 1996 Toth Istvan <stoty@vma.bme.hu>
  6.  Copyright (c) 1999 William McBrine <wmcbrine@clark.net>
  7.  
  8.  Distributed under the GNU General Public License.
  9.  For details, see the file COPYING in the parent directory. */
  10.  
  11. #include "mmail.h"
  12. #include "../interfac/error.h"
  13.  
  14. /* Default filenames. Note that EMX now serves for the Win32 port (via
  15.    RSXNT), as well as for OS/2; one of the few differences is the default
  16.    editor defined here:
  17. */
  18.  
  19. #ifdef __MSDOS__
  20. # define DEFEDIT "edit"
  21. # define DEFZIP "pkzip -o"
  22. # define DEFUNZIP "pkunzip -o"
  23. # define DEFLHA "lha a /m"
  24. # define DEFUNLHA "lha e"
  25. #else
  26. # ifdef __EMX__
  27. #  ifdef __WIN32__
  28. #   define DEFEDIT "edit"
  29. #  else
  30. #   define DEFEDIT "tedit"
  31. #  endif
  32. # else
  33. #  define DEFEDIT "vi"
  34. # endif
  35. # define DEFZIP "zip -jo"
  36. # define DEFUNZIP "unzip -joL"
  37. # define DEFLHA "lha af"
  38. # define DEFUNLHA "lha efi"
  39. #endif
  40.  
  41. #define DEFARJ "arj a -e"
  42. #define DEFUNARJ "arj e"
  43. #define DEFRAR "rar u -ep"
  44. #define DEFUNRAR "rar e -cl -o+"
  45.  
  46. #define DEFNONE "xxcompress"
  47. #define DEFUNNONE "xxuncompress"
  48.  
  49. #if defined (__MSDOS__) || defined (__EMX__)
  50. # define RCNAME "mmail.rc"
  51. # define ADDRBOOK "address.bk"
  52. # define SIGNATURE "sig.txt"
  53. #else
  54. # define RCNAME ".mmailrc"
  55. # define ADDRBOOK "addressbook"
  56. # define SIGNATURE ".signature"
  57. #endif
  58.  
  59. // ================
  60. // baseconfig class
  61. // ================
  62.  
  63. baseconfig::~baseconfig()
  64. {
  65. }
  66.  
  67. bool baseconfig::parseConfig(const char *configFileName)
  68. {
  69.     FILE *configFile;
  70.     char buffer[256], *pos, *resName, *resValue;
  71.     int vermajor = 0, verminor = 0;
  72.  
  73.     if ((configFile = fopen(configFileName, "rt"))) {
  74.         while (fgets(buffer, sizeof buffer, configFile)) {
  75.         if ((buffer[0] != '#') && (buffer[0] != '\n')) {
  76.             pos = buffer;
  77.  
  78.             //leading spaces
  79.             while (*pos == ' ' || *pos == '\t')
  80.                 pos++;
  81.  
  82.             //skip "bw" -- for backwards compatiblity
  83.             if (*pos == 'b' && pos[1] == 'w')
  84.                 pos += 2;
  85.  
  86.             //resName
  87.             resName = pos;
  88.             while (*pos != ':' && *pos != '=' &&
  89.                 *pos != ' ' && *pos != '\t' && *pos)
  90.                     pos++;
  91.             if (*pos)
  92.                 *pos++ = '\0';
  93.  
  94.             //chars between strings
  95.             while (*pos == ' ' || *pos == '\t' ||
  96.                 *pos == ':' || *pos == '=')
  97.                     pos++;
  98.  
  99.             //resValue
  100.             resValue = pos;
  101.             while (*pos != '\n' && *pos)
  102.                 pos++;
  103.             *pos = '\0';
  104.  
  105.             if (!strncasecmp("ver", resName, 3))
  106.                 sscanf(resValue, "%d.%d", &vermajor,
  107.                     &verminor);
  108.             else
  109.                 for (int c = 0; c < configItemNum; c++)
  110.                     if (!strcasecmp(names[c], resName)) {
  111.                         processOne(c, resValue);
  112.                         break;
  113.                     }
  114.         }
  115.         }
  116.         fclose(configFile);
  117.     }
  118.  
  119.     // Does the config file need updating?
  120.     return (vermajor < MM_MAJOR) || ((vermajor == MM_MAJOR) &&
  121.         (verminor < MM_MINOR));
  122. }
  123.  
  124. void baseconfig::newConfig(const char *configname)
  125. {
  126.     FILE *fd;
  127.     const char **p;
  128.  
  129.     printf("Updating %s...\n", configname);
  130.  
  131.     if ((fd = fopen(configname, "wt"))) {
  132.  
  133.         for (p = intro; *p; p++)
  134.             fprintf(fd, "# %s\n", *p);
  135.  
  136.         fprintf(fd, "\nVersion: %d.%d\n", MM_MAJOR, MM_MINOR);
  137.  
  138.         for (int x = 0; x < configItemNum; x++) {
  139.             if (comments[x])
  140.                 fprintf(fd, "\n# %s\n", comments[x]);
  141.             fprintf(fd, "%s: %s\n", names[x],
  142.                 configLineOut(x));
  143.         }
  144.         fclose(fd);
  145.     } else
  146.         fatalError("Error writing config file");
  147. }
  148.  
  149. // ==============
  150. // resource class
  151. // ==============
  152.  
  153. const int startUpLen = 31;
  154.  
  155. const char *resource::rc_names[startUpLen] =
  156. {
  157.     "homeDir", "mmHomeDir", "signature", "editor",
  158.     "PacketDir", "ReplyDir", "SaveDir", "AddressBook", "TaglineFile",
  159.      "ColorFile", "arjUncompressCommand", "zipUncompressCommand",
  160.     "lhaUncompressCommand", "rarUncompressCommand",
  161.     "unknownUncompressCommand", "arjCompressCommand",
  162.     "zipCompressCommand", "lhaCompressCommand", "rarCompressCommand",
  163.     "unknownCompressCommand", "PacketSort", "LetterSort", "Charset",
  164.     "UseTaglines", "AutoSaveReplies", "AutoSaveRead", "StripSoftCR",
  165.     "BeepOnPers", "UseLynxNav", "UseScrollBars", "MaxLines"
  166. };
  167.  
  168. const char *resource::rc_intro[] = {
  169.  "-----------------------",
  170.  MM_NAME " configuration",
  171.  "-----------------------",
  172.  "",
  173.  "Any of these keywords may be omitted, in which case the default values",
  174.  "(shown here) will be used.",
  175.  "",
  176.  "If you change either of the base directories, all the subsequent paths",
  177.  "will be changed, unless they're overriden in the individual settings.",
  178.  0
  179. };
  180.  
  181. const char *resource::rc_comments[startUpLen] = {
  182.  "Base directories (derived from $HOME or $MMAIL)", 0,
  183.  "Signature (file) that should be appended to each message. (Not used\n"
  184.  "# unless specified here.)",
  185.  "Editor for replies = $EDITOR; or if not defined, " DEFEDIT,
  186.  MM_NAME " will look for packets here",
  187.  "Reply packets go here",
  188.  "Saved messages go here, by default",
  189.  "Full paths to the address book and tagline file", 0,
  190.  "Full path to color specification file",
  191.  "Decompression commands (must include an option to junk/discard paths!)",
  192.     0, 0, 0, 0,
  193.  "Compression commands (must include an option to junk/discard paths!)",
  194.     0, 0, 0, 0,
  195.  "Default sort for packet list: by Name or Time (most recent first)",
  196.  "Default sort for letter list: by Subject, Number, From or To",
  197.  "Console character set: CP437 (IBM PC) or Latin-1 (ISO-8859-1)",
  198.  "Prompt to add taglines to replies?",
  199.  "Save replies after editing without prompting?",
  200.  "Save lastread pointers without prompting?",
  201.  "Strip \"soft carriage returns\" (char 141) from messages?",
  202.  "Beep when a personal message is opened in the letter window?",
  203.  "Use Lynx-like navigation (right arrow selects, left backs out)?",
  204.  "Put scroll bars on list windows when items exceed window lines?",
  205.  "Maximum lines per part for reply split (see docs)"
  206. };
  207.  
  208. const int resource::startUp[startUpLen] =
  209. {
  210.     homeDir, mmHomeDir, sigFile, editor,
  211.     PacketDir, ReplyDir, SaveDir, AddressFile, TaglineFile,
  212.     ColorFile, arjUncompressCommand, zipUncompressCommand,
  213.     lhaUncompressCommand, rarUncompressCommand,
  214.     unknownUncompressCommand, arjCompressCommand, zipCompressCommand,
  215.     lhaCompressCommand, rarCompressCommand, unknownCompressCommand,
  216.     PacketSort, LetterSort, Charset, UseTaglines, AutoSaveReplies,
  217.     AutoSaveRead, StripSoftCR, BeepOnPers, UseLynxNav, UseScrollBars,
  218.     MaxLines
  219. };
  220.  
  221. const int resource::defInt[] =
  222. {
  223.     1,    // PacketSort == by time
  224.     0,    // LetterSort == by subject
  225. #if defined (__MSDOS__) || defined (__EMX__)
  226.     0,    // Charset == CP437
  227. #else
  228.     1,    // Charset == Latin-1
  229. #endif
  230.     1,    // UseTaglines == Yes
  231.     0,    // AutoSaveReplies == No
  232.     0,    // AutoSaveRead == No
  233.     0,    // StripSoftCR == No
  234.     0,    // BeepOnPers == No
  235.     0,    // UseLynxNav == No
  236.     1,    // UseScrollBars == Yes
  237.     0    // MaxLines == disabled
  238. };
  239.  
  240. resource::resource()
  241. {
  242.     char configFileName[256], inp;
  243.     const char *envhome, *greeting =
  244.         "\nWelcome to " MM_NAME " v%d.%d!\n\n"
  245.         "A new or updated " RCNAME " has been written. "
  246.         "If you continue now, " MM_NAME " will\nuse the default "
  247.         "values for any new keywords. (Existing keywords have been "
  248.         "\npreserved.) If you wish to edit your " RCNAME " first, "
  249.         "say 'N' at the prompt.\n\nContinue? (y/n) ";
  250.  
  251.     names = rc_names;
  252.     intro = rc_intro;
  253.     comments = rc_comments;
  254.     configItemNum = startUpLen;
  255.  
  256.     for (int c = 0; c < noOfStrings; c++)
  257.         resourceData[c] = 0;
  258.     for (int c = noOfStrings; c < noOfResources; c++) {
  259.         int d = c - noOfStrings;
  260.         resourceInt[d] = defInt[d];
  261.     }
  262.     envhome = getenv("MMAIL");
  263.     if (!envhome)
  264.         envhome = getenv("HOME");
  265.     if (!envhome)
  266.         envhome = error.getOrigDir();
  267.  
  268.     set(homeDir, fixPath(envhome));
  269.     sprintf(configFileName, "%.243s/" RCNAME, get(homeDir));
  270.  
  271.     initinit();
  272.     homeInit();
  273.     mmHomeInit();
  274.  
  275.     if (parseConfig(configFileName)) {
  276.         newConfig(configFileName);
  277.         printf(greeting, MM_MAJOR, MM_MINOR);
  278.         inp = fgetc(stdin);
  279.         if (toupper(inp) == 'N')
  280.             exit(1);
  281.     }
  282.  
  283.     if (!verifyPaths())
  284.         fatalError("Unable to access data directories");
  285.  
  286.     mytmpnam(basedir);
  287.     checkPath(basedir, false);
  288.     subPath(WorkDir, "work");
  289.     subPath(UpWorkDir, "upwork");
  290. }
  291.  
  292. resource::~resource()
  293. {
  294.     clearDirectory(resourceData[WorkDir]);
  295.     clearDirectory(resourceData[UpWorkDir]);
  296.     mychdir("..");
  297.     myrmdir(resourceData[WorkDir]);
  298.     myrmdir(resourceData[UpWorkDir]);
  299.     mychdir("..");
  300.     myrmdir(basedir);
  301.     for (int c = 0; c < noOfStrings; c++)
  302.         delete[] resourceData[c];
  303. }
  304.  
  305. // For consistency, no path should end in a slash:
  306. const char *resource::fixPath(const char *path)
  307. {
  308.     static char tmp[256];
  309.     char d = path[strlen(path) - 1];
  310.  
  311.     if ((d == '/') || (d == '\\')) {
  312.         sprintf(tmp, "%.254s.", path); 
  313.         return tmp;
  314.     } else
  315.         return path;
  316. }
  317.  
  318. bool resource::checkPath(const char *onepath, bool show)
  319. {
  320.     if (mychdir(onepath)) {
  321.         if (show)
  322.             printf("Creating %s...\n", onepath);
  323.         if (mymkdir(onepath))
  324.             return false;
  325.     }
  326.     return true;
  327. }
  328.  
  329. bool resource::verifyPaths()
  330. {
  331.     if (checkPath(resourceData[mmHomeDir], true))
  332.         if (checkPath(resourceData[PacketDir], true))
  333.         if (checkPath(resourceData[ReplyDir], true))
  334.             if (checkPath(resourceData[SaveDir], true))
  335.             return true;
  336.     return false;
  337. }
  338.  
  339. void resource::processOne(int c, const char *resValue)
  340. {
  341.     if (*resValue) {
  342.         c = startUp[c];
  343.         if (c < noOfStrings) {
  344.             // Canonized for the benefit of the Win32 version:
  345.             set(c, canonize(fixPath(resValue)));
  346.             switch (c) {
  347.             case homeDir:
  348.                 homeInit();
  349.             case mmHomeDir:
  350.                 mmHomeInit();
  351.             }
  352.         } else {
  353.             int x = 0;
  354.             char r = toupper(*resValue);
  355.  
  356.             switch (c) {
  357.             case PacketSort:
  358.                 x = (r == 'T');
  359.                 break;
  360.             case LetterSort:
  361.                 switch (r) {
  362.                 case 'N':
  363.                     x = 1;
  364.                     break;
  365.                 case 'F':
  366.                     x = 2;
  367.                     break;
  368.                 case 'T':
  369.                     x = 3;
  370.                 }
  371.                 break;
  372.             case Charset:
  373.                 x = (r == 'L');
  374.                 break;
  375.             case MaxLines:
  376.                 sscanf(resValue, "%d", &x);
  377.                 break;
  378.             default:
  379.                 x = (r == 'Y');
  380.             }
  381.  
  382.             set(c, x);
  383.         }
  384.     }
  385. }
  386.  
  387. const char *resource::configLineOut(int x)
  388. {
  389.     static const char *pktopt[] = {"Name", "Time"},
  390.         *lttopt[] = {"Subject", "Number", "From", "To"},
  391.         *charopt[] = {"CP437", "Latin-1"},
  392.         *stdopt[] = {"No", "Yes"};
  393.  
  394.     x = startUp[x];
  395.  
  396.     if (x == MaxLines) {
  397.         static char value[8];
  398.         sprintf(value, "%d", getInt(x));
  399.         return value;
  400.     } else
  401.         return (x < noOfStrings) ? get(x) : ((x == PacketSort) ?
  402.             pktopt : ((x == LetterSort) ? lttopt : ((x == Charset) ?
  403.                 charopt : stdopt)))[getInt(x)];
  404. }
  405.  
  406. const char *resource::get(int ID) const
  407. {
  408.     return resourceData[ID];
  409. }
  410.  
  411. int resource::getInt(int ID) const
  412. {
  413.     ID -= noOfStrings;
  414.     return resourceInt[ID];
  415. }
  416.  
  417. void resource::set(int ID, const char *newValue)
  418. {
  419.     delete[] resourceData[ID];
  420.     resourceData[ID] = strdupplus(newValue);
  421. }
  422.  
  423. void resource::set(int ID, int newValue)
  424. {
  425.     ID -= noOfStrings;
  426.     resourceInt[ID] = newValue;
  427. }
  428.  
  429. //------------------------------------------------------------------------
  430. // The resource initializer functions
  431. //------------------------------------------------------------------------
  432.  
  433. void resource::homeInit()
  434. {
  435.     char tmp[256];
  436.  
  437.     sprintf(tmp, "%.243s/mmail", resourceData[homeDir]);
  438.     set(mmHomeDir, tmp);
  439. }
  440.  
  441. void resource::mmEachInit(int index, const char *dirname)
  442. {
  443.     char tmp[256];
  444.  
  445.     sprintf(tmp, "%.243s/%s", resourceData[mmHomeDir], dirname);
  446.     set(index, tmp);
  447. }
  448.  
  449. void resource::subPath(int index, const char *dirname)
  450. {
  451.     char tmp[256];
  452.  
  453.     sprintf(tmp, "%.243s/%s", basedir, dirname);
  454.     set(index, tmp);
  455.     if (!checkPath(tmp, 0))
  456.         fatalError("tmp Dir could not be created");
  457. }
  458.  
  459. void resource::initinit()
  460. {
  461.     set(arjUncompressCommand, DEFUNARJ);
  462.     set(zipUncompressCommand, DEFUNZIP);
  463.     set(lhaUncompressCommand, DEFUNLHA);
  464.     set(rarUncompressCommand, DEFUNRAR);
  465.     set(unknownUncompressCommand, DEFUNNONE);
  466.     set(arjCompressCommand, DEFARJ);
  467.     set(zipCompressCommand, DEFZIP);
  468.     set(lhaCompressCommand, DEFLHA);
  469.     set(rarCompressCommand, DEFRAR);
  470.     set(unknownCompressCommand, DEFNONE);
  471.  
  472.     set(UncompressCommand, DEFUNZIP);
  473.     set(CompressCommand, DEFZIP);
  474.  
  475.     set(sigFile, "");
  476.  
  477.     char *p = getenv("EDITOR");
  478.     set(editor, (p ? p : DEFEDIT));
  479. }
  480.  
  481. void resource::mmHomeInit()
  482. {
  483.     mmEachInit(PacketDir, "down");
  484.     mmEachInit(ReplyDir, "up");
  485.     mmEachInit(SaveDir, "save");
  486.     mmEachInit(AddressFile, ADDRBOOK);
  487.     mmEachInit(TaglineFile, "taglines");
  488.     mmEachInit(ColorFile, "colors");
  489. }
  490.