]> Pileus Git - ~andy/fetchmail/blobdiff - conf.c
Note Earl's regression fix for SSL_CTX_clear_options() on older OpenSSL.
[~andy/fetchmail] / conf.c
diff --git a/conf.c b/conf.c
index e875cfbc940ac7d45f61fba55c78d77ca19106a6..e51c7ccb3ef609bd9b8ea673a7ce1875af9d6aaf 100644 (file)
--- a/conf.c
+++ b/conf.c
@@ -1,5 +1,5 @@
 /*
- * conf.c -- main driver module for fetchmailconf
+ * conf.c -- dump fetchmail configuration as Python dictionary initializer
  *
  * For license terms, see the file COPYING in this directory.
  */
 
 #include "fetchmail.h"
 
+/* Python prettyprinting functions */
+
+static int indent_level;
+
+static void indent(char ic)
+/* indent current line */
+{
+    int        i;
+
+    if (ic == ')' || ic == ']' || ic == '}')
+       indent_level--;
+
+    /*
+     * The guard here is a kluge.  It depends on the fact that in the
+     * particular structure we're dumping, opening [s are always
+     * initializers for dictionary members and thus will be preceded
+     * by a member name.
+     */
+    if (ic != '[')
+    {
+       for (i = 0; i < indent_level / 2; i++)
+           putc('\t', stdout);
+       if (indent_level % 2)
+           fputs("    ", stdout);
+    }
+
+    if (ic)
+    {
+       putc(ic, stdout);
+       putc('\n', stdout);
+    }
+
+    if (ic == '(' || ic == '[' || ic == '{')
+       indent_level++;
+}
+
+
+static void stringdump(const char *name, const char *member)
+/* dump a string member with current indent */
+{
+    indent('\0');
+    fprintf(stdout, "\"%s\":", name);
+    if (member)
+       fprintf(stdout, "\"%s\"", visbuf(member));
+    else
+       fputs("None", stdout);
+    fputs(",\n", stdout);
+}
+
+static void numdump(const char *name, const int num)
+/* dump a numeric quantity at current indent */
+{
+    indent('\0');
+    fprintf(stdout, "'%s':%d,\n", name, NUM_VALUE_OUT(num));
+}
+
+static void booldump(const char *name, const int onoff)
+/* dump a boolean quantity at current indent */
+{
+    indent('\0');
+    if (onoff)
+       fprintf(stdout, "'%s':TRUE,\n", name);
+    else
+       fprintf(stdout, "'%s':FALSE,\n", name);
+}
+
+static void listdump(const char *name, struct idlist *list)
+/* dump a string list member with current indent */
+{
+    indent('\0');
+    fprintf(stdout, "\"%s\":", name);
+
+    if (!list)
+       fputs("[],\n", stdout);
+    else
+    {
+       struct idlist *idp;
+
+       fputs("[", stdout);
+       for (idp = list; idp; idp = idp->next)
+           if (idp->id)
+           {
+               fprintf(stdout, "\"%s\"", visbuf(idp->id));
+               if (idp->next)
+                   fputs(", ", stdout);
+           }
+       fputs("],\n", stdout);
+    }
+}
+
 /*
  * Note: this function dumps the entire configuration,
  * after merging of the defaults record (if any).  It
@@ -33,22 +123,100 @@ void dump_config(struct runctl *runp, struct query *querylist)
 {
     struct query *ctl;
     struct idlist *idp;
-    time_t now;
-
-    /* now write the edited configuration back to the file */
-    time(&now);
-    fprintf(stdout, "# fetchmail rc file generated at %s", ctime(&now));
-
-    if (runp->poll_interval)
-       fprintf(stdout, "set daemon %d\n", runp->poll_interval);
-    if (runp->use_syslog)
-       fprintf(stdout, "set syslog\n");
-    if (runp->logfile)
-       fprintf(stdout, "set logfile %s\n", runp->logfile);
-    if (runp->idfile)
-       fprintf(stdout, "set idfile %s\n", runp->idfile);
-    if (runp->invisible)
-       fprintf(stdout, "set invisible\n");
+    const char *features;
+
+    indent_level = 0;
+
+    /*
+     * These had better match the values fetchmailconf is expecting!
+     * (We don't want to import them from Tkinter because the user
+     * might not have it installed.)
+     */
+    fputs("TRUE=1; FALSE=0\n\n", stdout);
+
+    /*
+     * We need this in order to know whether `interface' and `monitor'
+     * are valid options or not.
+     */
+#if defined(linux)
+    fputs("os_type = 'linux'\n", stdout);
+#elif defined(__FreeBSD__)
+    fputs("os_type = 'freebsd'\n", stdout);
+#else
+    fputs("os_type = 'generic'\n", stdout);
+#endif
+
+    /* 
+     * This should be approximately in sync with the -V option dumping 
+     * in fetchmail.c.
+     */
+    features = "feature_options = ("
+#ifdef POP2_ENABLE
+    "'pop2',"
+#endif /* POP2_ENABLE */
+#ifdef POP3_ENABLE
+    "'pop3',"
+#endif /* POP3_ENABLE */
+#ifdef IMAP_ENABLE
+    "'imap',"
+#endif /* IMAP_ENABLE */
+#ifdef GSSAPI
+    "'gssapi',"
+#endif /* GSSAPI */
+#if defined(KERBEROS_V4)
+    "'kerberos',"
+#endif /* defined(IMAP4) */
+#ifdef RPA_ENABLE
+    "'rpa',"
+#endif /* RPA_ENABLE */
+#ifdef SDPS_ENABLE
+    "'sdps',"
+#endif /* SDPS_ENABLE */
+#ifdef ETRN_ENABLE
+    "'etrn',"
+#endif /* ETRN_ENABLE */
+#ifdef ODMR_ENABLE
+    "'odmr',"
+#endif /* ODMR_ENABLE */
+#ifdef SSL_ENABLE
+    "'ssl',"
+#endif /* SSL_ENABLE */
+#ifdef OPIE_ENABLE
+    "'opie',"
+#endif /* OPIE_ENABLE */
+#ifdef HAVE_SOCKS
+    "'socks',"
+#endif /* HAVE_SOCKS */
+    ")\n";
+    fputs(features, stdout);
+
+    fputs("# Start of configuration initializer\n", stdout);
+    fputs("fetchmailrc = ", stdout);
+    indent('{');
+
+    numdump("poll_interval", runp->poll_interval);
+    stringdump("logfile", runp->logfile);
+    stringdump("idfile", runp->idfile);
+    stringdump("postmaster", runp->postmaster);
+    booldump("bouncemail", runp->bouncemail);
+    booldump("spambounce", runp->spambounce);
+    booldump("softbounce", runp->softbounce);
+    stringdump("properties", runp->properties);
+    booldump("invisible", runp->invisible);
+    booldump("showdots", runp->showdots);
+    booldump("syslog", runp->use_syslog);
+
+    if (!querylist)
+    {
+       fputs("    'servers': []\n", stdout);
+       goto alldone;
+    }
+
+    indent(0);
+    fputs("# List of server entries begins here\n", stdout);
+    indent(0);
+    fputs("'servers': ", stdout);
+    indent('[');
 
     for (ctl = querylist; ctl; ctl = ctl->next)
     {
@@ -57,171 +225,200 @@ void dump_config(struct runctl *runp, struct query *querylist)
         */
        if (!ctl->server.lead_server)
        {
-           flag using_kpop =
-               (ctl->server.protocol == P_POP3 &&
-                ctl->server.port == KPOP_PORT &&
-                ctl->server.preauthenticate == A_KERBEROS_V4);
+           flag        using_kpop;
 
-           if (strcmp(ctl->server.pollname, "defaults") == 0)
-               fputs("defaults ", stdout);
-           else
-               fprintf(stdout, "%s %s ",
-                   ctl->server.skip ? "skip" : "poll",
-                   visbuf(ctl->server.pollname));
-           if (ctl->server.via)
-               fprintf(stdout, "via %s ", ctl->server.via);
-           if (ctl->server.protocol != P_AUTO)
-               fprintf(stdout, "with protocol %s ",
-                       using_kpop ? "KPOP" : showproto(ctl->server.protocol));
-           if (ctl->server.port)
-               fprintf(stdout, "port %d ", ctl->server.port);
-           if (ctl->server.timeout)
-               fprintf(stdout, "timeout %d ", ctl->server.timeout);
-           if (ctl->server.interval)
-               fprintf(stdout, "interval %d ", ctl->server.interval);
-           if (ctl->server.envelope == STRING_DISABLED)
-               fprintf(stdout, "no envelope ");
-           else if (ctl->server.envelope)
-               fprintf(stdout, "envelope \"%s\" ", visbuf(ctl->server.envelope));
-           if (ctl->server.qvirtual)
-               fprintf(stdout, "qvirtual \"%s\" ", visbuf(ctl->server.qvirtual));
-           if (ctl->server.preauthenticate == A_KERBEROS_V4)
-               fprintf(stdout, "auth kerberos_v4 ");
-#define DUMPOPT(flag, str) \
-               if (flag) \
-                   fprintf(stdout, "%s ", str); \
-               else \
-                   fprintf(stdout, "no %s ", str);
-#if defined(HAVE_GETHOSTBYNAME) && defined(HAVE_RES_SEARCH)
-           if (ctl->server.dns || ctl->server.uidl)
-#else
-           if (ctl->server.uidl)
-#endif /* HAVE_GETHOSTBYNAME && HAVE_RES_SEARCH */
-               fputs("and options ", stdout);
-#if defined(HAVE_GETHOSTBYNAME) && defined(HAVE_RES_SEARCH)
-           DUMPOPT(ctl->server.dns,  "dns");
-#endif /* HAVE_GETHOSTBYNAME && HAVE_RES_SEARCH */
-           DUMPOPT(ctl->server.uidl, "uidl");
-           fputs("\n", stdout);
-
-           /* AKA and loca-domain declarations */
-           if (ctl->server.akalist || ctl->server.localdomains)
+           /*
+            * Every time we see a leading server entry after the first one,
+            * it implicitly ends the both (a) the list of user structures
+            * associated with the previous entry, and (b) that previous entry.
+            */
+           if (ctl > querylist)
            {
-               fputc('\t', stdout);
-               if (ctl->server.akalist)
-               {
-                   struct idlist *idp;
-
-                   fprintf(stdout, "aka");
-                   for (idp = ctl->server.akalist; idp; idp = idp->next)
-                       fprintf(stdout, " %s", visbuf(idp->id));
-               }
-
-               if (ctl->server.akalist && ctl->server.localdomains)
-                   putc(' ', stdout);
-
-               if (ctl->server.localdomains)
-               {
-                   struct idlist *idp;
-
-                   fprintf(stdout, "localdomains");
-                   for (idp = ctl->server.localdomains; idp; idp = idp->next)
-                       fprintf(stdout, " %s", visbuf(idp->id));
-               }
+               indent(']');
+               indent('}');
+               indent('\0'); 
+               putc(',', stdout);
                putc('\n', stdout);
            }
 
-#ifdef linux
-           if (ctl->server.monitor || ctl->server.interface)
-           {
-               putc('\t', stdout);
-               if (ctl->server.monitor)
-                   fprintf(stdout, "monitor \"%s\" ", ctl->server.monitor);
-               if (ctl->server.interface)
-                   fprintf(stdout, "interface \"%s\"", ctl->server.interface);
-               putc('\n', stdout);
-           }
-#endif /* linux */
-       }
+           indent(0);
+           fprintf(stdout,"# Entry for site `%s' begins:\n",ctl->server.pollname);
+           indent('{');
 
-       fputc('\t', stdout);
-       if (ctl->remotename || ctl->password || ctl->localnames)
-       {
-           if (ctl->remotename)
-               fprintf(stdout, "user \"%s\" ", visbuf(ctl->remotename));
-           if (ctl->remotename && ctl->password)
-               fputs("with ", stdout);
-           if (ctl->password)
-               fprintf(stdout, "password \"%s\" ", visbuf(ctl->password));
-           if (ctl->localnames)
-           {
-               fprintf(stdout, "is ");
-               for (idp = ctl->localnames; idp; idp = idp->next)
-                   if (idp->val.id2)
-                       fprintf(stdout, "\"%s\"=\"%s\" ", 
-                               visbuf(idp->id), visbuf(idp->val.id2));
-                   else
-                       fprintf(stdout, "%s ", visbuf(idp->id));
-               if (ctl->wildcard)
-                   fputs("*", stdout);
+           using_kpop =
+               (ctl->server.protocol == P_POP3 &&
+                ctl->server.service && !strcmp(ctl->server.service, KPOP_PORT ) &&
+                ctl->server.authenticate == A_KERBEROS_V4);
+
+           stringdump("pollname", ctl->server.pollname); 
+           booldump("active", !ctl->server.skip); 
+           stringdump("via", ctl->server.via); 
+           stringdump("protocol", 
+                      using_kpop ? "KPOP" : showproto(ctl->server.protocol));
+           stringdump("service",  ctl->server.service);
+           numdump("timeout",  ctl->server.timeout);
+           numdump("interval", ctl->server.interval);
+
+           if (ctl->server.envelope == STRING_DISABLED)
+               stringdump("envelope", NULL); 
+           else if (ctl->server.envelope == NULL)
+               stringdump("envelope", "Received");             
+           else
+               stringdump("envelope", ctl->server.envelope); 
+           numdump("envskip", ctl->server.envskip);
+           stringdump("qvirtual", ctl->server.qvirtual);
+           if (ctl->server.authenticate == A_ANY)
+               stringdump("auth", "any");
+           else if (ctl->server.authenticate == A_PASSWORD)
+               stringdump("auth", "password");
+           else if (ctl->server.authenticate == A_NTLM)
+               stringdump("auth", "ntlm");
+           else if (ctl->server.authenticate == A_CRAM_MD5)
+               stringdump("auth", "cram-md5");
+           else if (ctl->server.authenticate == A_GSSAPI)
+               stringdump("auth", "gssapi");
+           else if (ctl->server.authenticate == A_KERBEROS_V4)
+               stringdump("auth", "kerberos_v4");
+           else if (ctl->server.authenticate == A_KERBEROS_V5)
+               stringdump("auth", "kerberos_v5");
+           else if (ctl->server.authenticate == A_SSH)
+               stringdump("auth", "ssh");
+           else if (ctl->server.authenticate == A_OTP)
+               stringdump("auth", "otp");
+           else if (ctl->server.authenticate == A_MSN)
+               stringdump("auth", "msn");
+
+#ifdef HAVE_RES_SEARCH
+           booldump("dns", ctl->server.dns);
+#endif /* HAVE_RES_SEARCH */
+           booldump("uidl", ctl->server.uidl);
+
+           listdump("aka", ctl->server.akalist);
+           listdump("localdomains", ctl->server.localdomains);
+
+#ifdef CAN_MONITOR
+           stringdump("interface", ctl->server.interface);
+           stringdump("monitor", ctl->server.monitor);
+#endif
+
+           stringdump("plugin", ctl->server.plugin);
+           stringdump("plugout", ctl->server.plugout);
+           stringdump("principal", ctl->server.principal);
+           if (ctl->server.esmtp_name)
+               stringdump("esmtpname",ctl->server.esmtp_name);
+           if (ctl->server.esmtp_password)
+               stringdump("esmtppassword",ctl->server.esmtp_password);
+           booldump("tracepolls", ctl->server.tracepolls);
+           indent(0);
+           switch(ctl->server.badheader) {
+               /* this is a hack - we map this to a boolean option for
+                * fetchmailconf purposes */
+               case BHREJECT: puts("'badheader': FALSE,"); break;
+               case BHACCEPT: puts("'badheader': TRUE,"); break;
            }
+
+           indent(0);
+           fputs("'users': ", stdout);
+           indent('[');
        }
 
-       if (ctl->fetchall || ctl->keep || ctl->flush || ctl->rewrite
-                       || ctl->stripcr || ctl->forcecr || ctl->pass8bits)
-           fputs("options ", stdout);
-       DUMPOPT(ctl->fetchall,    "fetchall");
-       DUMPOPT(ctl->keep,        "keep");
-       DUMPOPT(ctl->flush,       "flush");
-       DUMPOPT(ctl->rewrite,     "rewrite");
-       DUMPOPT(ctl->stripcr,     "stripcr"); 
-       DUMPOPT(ctl->forcecr,     "forcecr");
-       DUMPOPT(ctl->pass8bits,   "pass8bits");
-       DUMPOPT(ctl->dropstatus,  "dropstatus");
-       DUMPOPT(ctl->mimedecode,  "mimedecode");
-#undef DUMPOPT
-
-       if (ctl->mda)
-           fprintf(stdout, "mda \"%s\" ", visbuf(ctl->mda));
-#ifdef INET6
-       if (ctl->netsec)
-           fprintf(stdout, "netsec \"%s\" ", visbuf(ctl->netsec));
-#endif /* INET6 */
-       if (ctl->preconnect)
-           fprintf(stdout, "preconnect \"%s\" ", visbuf(ctl->preconnect));     
-       if (ctl->postconnect)
-           fprintf(stdout, "postconnect \"%s\" ", visbuf(ctl->postconnect));   
-       if (ctl->fetchlimit)
-           fprintf(stdout, "fetchlimit %d ", ctl->fetchlimit);
-       if (ctl->batchlimit)
-           fprintf(stdout, "batchlimit %d ", ctl->batchlimit);
-
-       if (ctl->smtphunt)
+       indent('{');
+
+       stringdump("remote", ctl->remotename);
+       stringdump("password", ctl->password);
+
+       indent('\0');
+       fprintf(stdout, "'localnames':[");
+       for (idp = ctl->localnames; idp; idp = idp->next)
        {
-           struct idlist *idp;
+           char namebuf[USERNAMELEN + 1];
 
-           fprintf(stdout, "smtphost ");
-           for (idp = ctl->smtphunt; idp; idp = idp->next)
-               fprintf(stdout, "%s ", visbuf(idp->id));
+           strlcpy(namebuf, visbuf(idp->id), sizeof(namebuf));
+           if (idp->val.id2)
+               fprintf(stdout, "(\"%s\", %s)", namebuf, visbuf(idp->val.id2));
+           else
+               fprintf(stdout, "\"%s\"", namebuf);
+           if (idp->next)
+               fputs(", ", stdout);
        }
+       if (ctl->wildcard)
+           fputs(", '*'", stdout);
+       fputs("],\n", stdout);
 
-       if (ctl->smtpaddress)
-           fprintf(stdout, "smtpaddress \"%s\" ", visbuf(ctl->smtpaddress));
+       booldump("fetchall", ctl->fetchall);
+       booldump("keep", ctl->keep);
+       booldump("flush", ctl->flush);
+       booldump("limitflush", ctl->limitflush);
+       booldump("rewrite", ctl->rewrite);
+       booldump("stripcr", ctl->stripcr); 
+       booldump("forcecr", ctl->forcecr);
+       booldump("pass8bits", ctl->pass8bits);
+       booldump("dropstatus", ctl->dropstatus);
+       booldump("dropdelivered", ctl->dropdelivered);
+       booldump("mimedecode", ctl->mimedecode);
+       booldump("idle", ctl->idle);
 
-       if (ctl->antispam)
-           fprintf(stdout, "antispam %d ", ctl->antispam);
+       stringdump("mda", ctl->mda);
+       stringdump("bsmtp", ctl->bsmtp);
+       indent('\0');
+       if (ctl->listener == LMTP_MODE)
+           fputs("'lmtp':TRUE,\n", stdout);
+       else
+           fputs("'lmtp':FALSE,\n", stdout);
+           
+       stringdump("preconnect", ctl->preconnect);
+       stringdump("postconnect", ctl->postconnect);
+       numdump("limit", ctl->limit);
+       numdump("warnings", ctl->warnings);
+       numdump("fetchlimit", ctl->fetchlimit);
+       numdump("fetchsizelimit", ctl->fetchsizelimit);
+       numdump("fastuidl", ctl->fastuidl);
+       numdump("batchlimit", ctl->batchlimit);
+#ifdef SSL_ENABLE
+       booldump("ssl", ctl->use_ssl);
+       stringdump("sslkey", ctl->sslkey);
+       stringdump("sslcert", ctl->sslcert);
+       stringdump("sslproto", ctl->sslproto);
+       booldump("sslcertck", ctl->sslcertck);
+       stringdump("sslcertpath", ctl->sslcertpath);
+       stringdump("sslcommonname", ctl->sslcommonname);
+       stringdump("sslfingerprint", ctl->sslfingerprint);
+#endif /* SSL_ENABLE */
+       numdump("expunge", ctl->expunge);
+       stringdump("properties", ctl->properties);
+       listdump("smtphunt", ctl->smtphunt);
+       listdump("fetchdomains", ctl->domainlist);
+       stringdump("smtpaddress", ctl->smtpaddress);
+       stringdump("smtpname", ctl->smtpname);
 
-       if (ctl->mailboxes && ctl->mailboxes->id)
+       indent('\0');
+       fprintf(stdout, "'antispam':'");
+       for (idp = ctl->antispam; idp; idp = idp->next)
        {
-           struct idlist *idp;
-
-           fprintf(stdout, "mailboxes ");
-           for (idp = ctl->mailboxes; idp; idp = idp->next)
-               fprintf(stdout, "%s ", visbuf(idp->id));
+           fprintf(stdout, "%d", idp->val.status.num);
+           if (idp->next)
+               fputs(" ", stdout);
        }
+       fputs("',\n", stdout);
+       listdump("mailboxes", ctl->mailboxes);
 
-       putc('\n', stdout);
+       indent('}');
+       indent('\0'); 
+       fputc(',', stdout);
     }
+
+    /* end last span of user entries and last server entry */
+    indent(']');
+    indent('}');
+
+    /* end array of servers */
+    indent(']');
+
+ alldone:
+    /* end top-level dictionary */
+    indent('}');
+    fputs("# End of initializer\n", stdout);
 }
 
 /* conf.c ends here */