| 1 |
/* |
| 2 |
* conf.c -- dump fetchmail configuration as Python dictionary initializer |
| 3 |
* |
| 4 |
* For license terms, see the file COPYING in this directory. |
| 5 |
*/ |
| 6 |
|
| 7 |
#include "config.h" |
| 8 |
#include "tunable.h" |
| 9 |
|
| 10 |
#include <stdio.h> |
| 11 |
#include <ctype.h> |
| 12 |
#if defined(STDC_HEADERS) |
| 13 |
#include <stdlib.h> |
| 14 |
#endif |
| 15 |
#if defined(HAVE_UNISTD_H) |
| 16 |
#include <unistd.h> |
| 17 |
#endif |
| 18 |
#include <string.h> |
| 19 |
#include <pwd.h> |
| 20 |
#include <errno.h> |
| 21 |
|
| 22 |
#include "fetchmail.h" |
| 23 |
|
| 24 |
/* Python prettyprinting functions */ |
| 25 |
|
| 26 |
static int indent_level; |
| 27 |
|
| 28 |
static void indent(char ic) |
| 29 |
/* indent current line */ |
| 30 |
{ |
| 31 |
int i; |
| 32 |
|
| 33 |
if (ic == ')' || ic == ']' || ic == '}') |
| 34 |
indent_level--; |
| 35 |
|
| 36 |
/* |
| 37 |
* The guard here is a kluge. It depends on the fact that in the |
| 38 |
* particular structure we're dumping, opening [s are always |
| 39 |
* initializers for dictionary members and thus will be preceded |
| 40 |
* by a member name. |
| 41 |
*/ |
| 42 |
if (ic != '[') |
| 43 |
{ |
| 44 |
for (i = 0; i < indent_level / 2; i++) |
| 45 |
putc('\t', stdout); |
| 46 |
if (indent_level % 2) |
| 47 |
fputs(" ", stdout); |
| 48 |
} |
| 49 |
|
| 50 |
if (ic) |
| 51 |
{ |
| 52 |
putc(ic, stdout); |
| 53 |
putc('\n', stdout); |
| 54 |
} |
| 55 |
|
| 56 |
if (ic == '(' || ic == '[' || ic == '{') |
| 57 |
indent_level++; |
| 58 |
} |
| 59 |
|
| 60 |
|
| 61 |
static void stringdump(const char *name, const char *member) |
| 62 |
/* dump a string member with current indent */ |
| 63 |
{ |
| 64 |
indent('\0'); |
| 65 |
fprintf(stdout, "\"%s\":", name); |
| 66 |
if (member) |
| 67 |
fprintf(stdout, "\"%s\"", visbuf(member)); |
| 68 |
else |
| 69 |
fputs("None", stdout); |
| 70 |
fputs(",\n", stdout); |
| 71 |
} |
| 72 |
|
| 73 |
static void numdump(const char *name, const int num) |
| 74 |
/* dump a numeric quantity at current indent */ |
| 75 |
{ |
| 76 |
indent('\0'); |
| 77 |
fprintf(stdout, "'%s':%d,\n", name, NUM_VALUE_OUT(num)); |
| 78 |
} |
| 79 |
|
| 80 |
static void booldump(const char *name, const int onoff) |
| 81 |
/* dump a boolean quantity at current indent */ |
| 82 |
{ |
| 83 |
indent('\0'); |
| 84 |
if (onoff) |
| 85 |
fprintf(stdout, "'%s':TRUE,\n", name); |
| 86 |
else |
| 87 |
fprintf(stdout, "'%s':FALSE,\n", name); |
| 88 |
} |
| 89 |
|
| 90 |
static void listdump(const char *name, struct idlist *list) |
| 91 |
/* dump a string list member with current indent */ |
| 92 |
{ |
| 93 |
indent('\0'); |
| 94 |
fprintf(stdout, "\"%s\":", name); |
| 95 |
|
| 96 |
if (!list) |
| 97 |
fputs("[],\n", stdout); |
| 98 |
else |
| 99 |
{ |
| 100 |
struct idlist *idp; |
| 101 |
|
| 102 |
fputs("[", stdout); |
| 103 |
for (idp = list; idp; idp = idp->next) |
| 104 |
if (idp->id) |
| 105 |
{ |
| 106 |
fprintf(stdout, "\"%s\"", visbuf(idp->id)); |
| 107 |
if (idp->next) |
| 108 |
fputs(", ", stdout); |
| 109 |
} |
| 110 |
fputs("],\n", stdout); |
| 111 |
} |
| 112 |
} |
| 113 |
|
| 114 |
/* |
| 115 |
* Note: this function dumps the entire configuration, |
| 116 |
* after merging of the defaults record (if any). It |
| 117 |
* is intended to produce output parseable by a configuration |
| 118 |
* front end, not anything especially comfortable for humans. |
| 119 |
*/ |
| 120 |
|
| 121 |
void dump_config(struct runctl *runp, struct query *querylist) |
| 122 |
/* dump the in-core configuration in recompilable form */ |
| 123 |
{ |
| 124 |
struct query *ctl; |
| 125 |
struct idlist *idp; |
| 126 |
const char *features; |
| 127 |
|
| 128 |
indent_level = 0; |
| 129 |
|
| 130 |
/* |
| 131 |
* These had better match the values fetchmailconf is expecting! |
| 132 |
* (We don't want to import them from Tkinter because the user |
| 133 |
* might not have it installed.) |
| 134 |
*/ |
| 135 |
fputs("TRUE=1; FALSE=0\n\n", stdout); |
| 136 |
|
| 137 |
/* |
| 138 |
* We need this in order to know whether `interface' and `monitor' |
| 139 |
* are valid options or not. |
| 140 |
*/ |
| 141 |
#if defined(linux) |
| 142 |
fputs("os_type = 'linux'\n", stdout); |
| 143 |
#elif defined(__FreeBSD__) |
| 144 |
fputs("os_type = 'freebsd'\n", stdout); |
| 145 |
#else |
| 146 |
fputs("os_type = 'generic'\n", stdout); |
| 147 |
#endif |
| 148 |
|
| 149 |
/* |
| 150 |
* This should be approximately in sync with the -V option dumping |
| 151 |
* in fetchmail.c. |
| 152 |
*/ |
| 153 |
features = "feature_options = (" |
| 154 |
#ifdef POP2_ENABLE |
| 155 |
"'pop2'," |
| 156 |
#endif /* POP2_ENABLE */ |
| 157 |
#ifdef POP3_ENABLE |
| 158 |
"'pop3'," |
| 159 |
#endif /* POP3_ENABLE */ |
| 160 |
#ifdef IMAP_ENABLE |
| 161 |
"'imap'," |
| 162 |
#endif /* IMAP_ENABLE */ |
| 163 |
#ifdef GSSAPI |
| 164 |
"'gssapi'," |
| 165 |
#endif /* GSSAPI */ |
| 166 |
#if defined(KERBEROS_V4) |
| 167 |
"'kerberos'," |
| 168 |
#endif /* defined(IMAP4) */ |
| 169 |
#ifdef RPA_ENABLE |
| 170 |
"'rpa'," |
| 171 |
#endif /* RPA_ENABLE */ |
| 172 |
#ifdef SDPS_ENABLE |
| 173 |
"'sdps'," |
| 174 |
#endif /* SDPS_ENABLE */ |
| 175 |
#ifdef ETRN_ENABLE |
| 176 |
"'etrn'," |
| 177 |
#endif /* ETRN_ENABLE */ |
| 178 |
#ifdef ODMR_ENABLE |
| 179 |
"'odmr'," |
| 180 |
#endif /* ODMR_ENABLE */ |
| 181 |
#ifdef SSL_ENABLE |
| 182 |
"'ssl'," |
| 183 |
#endif /* SSL_ENABLE */ |
| 184 |
#ifdef OPIE_ENABLE |
| 185 |
"'opie'," |
| 186 |
#endif /* OPIE_ENABLE */ |
| 187 |
#ifdef HAVE_SOCKS |
| 188 |
"'socks'," |
| 189 |
#endif /* HAVE_SOCKS */ |
| 190 |
")\n"; |
| 191 |
fputs(features, stdout); |
| 192 |
|
| 193 |
fputs("# Start of configuration initializer\n", stdout); |
| 194 |
fputs("fetchmailrc = ", stdout); |
| 195 |
indent('{'); |
| 196 |
|
| 197 |
numdump("poll_interval", runp->poll_interval); |
| 198 |
stringdump("logfile", runp->logfile); |
| 199 |
stringdump("idfile", runp->idfile); |
| 200 |
stringdump("postmaster", runp->postmaster); |
| 201 |
booldump("bouncemail", runp->bouncemail); |
| 202 |
booldump("spambounce", runp->spambounce); |
| 203 |
booldump("softbounce", runp->softbounce); |
| 204 |
stringdump("properties", runp->properties); |
| 205 |
booldump("invisible", runp->invisible); |
| 206 |
booldump("showdots", runp->showdots); |
| 207 |
booldump("syslog", runp->use_syslog); |
| 208 |
|
| 209 |
if (!querylist) |
| 210 |
{ |
| 211 |
fputs(" 'servers': []\n", stdout); |
| 212 |
goto alldone; |
| 213 |
} |
| 214 |
|
| 215 |
indent(0); |
| 216 |
fputs("# List of server entries begins here\n", stdout); |
| 217 |
indent(0); |
| 218 |
fputs("'servers': ", stdout); |
| 219 |
indent('['); |
| 220 |
|
| 221 |
for (ctl = querylist; ctl; ctl = ctl->next) |
| 222 |
{ |
| 223 |
/* |
| 224 |
* First, the server stuff. |
| 225 |
*/ |
| 226 |
if (!ctl->server.lead_server) |
| 227 |
{ |
| 228 |
flag using_kpop; |
| 229 |
|
| 230 |
/* |
| 231 |
* Every time we see a leading server entry after the first one, |
| 232 |
* it implicitly ends the both (a) the list of user structures |
| 233 |
* associated with the previous entry, and (b) that previous entry. |
| 234 |
*/ |
| 235 |
if (ctl > querylist) |
| 236 |
{ |
| 237 |
indent(']'); |
| 238 |
indent('}'); |
| 239 |
indent('\0'); |
| 240 |
putc(',', stdout); |
| 241 |
putc('\n', stdout); |
| 242 |
} |
| 243 |
|
| 244 |
indent(0); |
| 245 |
fprintf(stdout,"# Entry for site `%s' begins:\n",ctl->server.pollname); |
| 246 |
indent('{'); |
| 247 |
|
| 248 |
using_kpop = |
| 249 |
(ctl->server.protocol == P_POP3 && |
| 250 |
ctl->server.service && !strcmp(ctl->server.service, KPOP_PORT ) && |
| 251 |
ctl->server.authenticate == A_KERBEROS_V4); |
| 252 |
|
| 253 |
stringdump("pollname", ctl->server.pollname); |
| 254 |
booldump("active", !ctl->server.skip); |
| 255 |
stringdump("via", ctl->server.via); |
| 256 |
stringdump("protocol", |
| 257 |
using_kpop ? "KPOP" : showproto(ctl->server.protocol)); |
| 258 |
stringdump("service", ctl->server.service); |
| 259 |
numdump("timeout", ctl->server.timeout); |
| 260 |
numdump("interval", ctl->server.interval); |
| 261 |
|
| 262 |
if (ctl->server.envelope == STRING_DISABLED) |
| 263 |
stringdump("envelope", NULL); |
| 264 |
else if (ctl->server.envelope == NULL) |
| 265 |
stringdump("envelope", "Received"); |
| 266 |
else |
| 267 |
stringdump("envelope", ctl->server.envelope); |
| 268 |
numdump("envskip", ctl->server.envskip); |
| 269 |
stringdump("qvirtual", ctl->server.qvirtual); |
| 270 |
|
| 271 |
if (ctl->server.authenticate == A_ANY) |
| 272 |
stringdump("auth", "any"); |
| 273 |
else if (ctl->server.authenticate == A_PASSWORD) |
| 274 |
stringdump("auth", "password"); |
| 275 |
else if (ctl->server.authenticate == A_NTLM) |
| 276 |
stringdump("auth", "ntlm"); |
| 277 |
else if (ctl->server.authenticate == A_CRAM_MD5) |
| 278 |
stringdump("auth", "cram-md5"); |
| 279 |
else if (ctl->server.authenticate == A_GSSAPI) |
| 280 |
stringdump("auth", "gssapi"); |
| 281 |
else if (ctl->server.authenticate == A_KERBEROS_V4) |
| 282 |
stringdump("auth", "kerberos_v4"); |
| 283 |
else if (ctl->server.authenticate == A_KERBEROS_V5) |
| 284 |
stringdump("auth", "kerberos_v5"); |
| 285 |
else if (ctl->server.authenticate == A_SSH) |
| 286 |
stringdump("auth", "ssh"); |
| 287 |
else if (ctl->server.authenticate == A_OTP) |
| 288 |
stringdump("auth", "otp"); |
| 289 |
else if (ctl->server.authenticate == A_MSN) |
| 290 |
stringdump("auth", "msn"); |
| 291 |
|
| 292 |
#ifdef HAVE_RES_SEARCH |
| 293 |
booldump("dns", ctl->server.dns); |
| 294 |
#endif /* HAVE_RES_SEARCH */ |
| 295 |
booldump("uidl", ctl->server.uidl); |
| 296 |
|
| 297 |
listdump("aka", ctl->server.akalist); |
| 298 |
listdump("localdomains", ctl->server.localdomains); |
| 299 |
|
| 300 |
#ifdef CAN_MONITOR |
| 301 |
stringdump("interface", ctl->server.interface); |
| 302 |
stringdump("monitor", ctl->server.monitor); |
| 303 |
#endif |
| 304 |
|
| 305 |
stringdump("plugin", ctl->server.plugin); |
| 306 |
stringdump("plugout", ctl->server.plugout); |
| 307 |
stringdump("principal", ctl->server.principal); |
| 308 |
if (ctl->server.esmtp_name) |
| 309 |
stringdump("esmtpname",ctl->server.esmtp_name); |
| 310 |
if (ctl->server.esmtp_password) |
| 311 |
stringdump("esmtppassword",ctl->server.esmtp_password); |
| 312 |
booldump("tracepolls", ctl->server.tracepolls); |
| 313 |
indent(0); |
| 314 |
switch(ctl->server.badheader) { |
| 315 |
/* this is a hack - we map this to a boolean option for |
| 316 |
* fetchmailconf purposes */ |
| 317 |
case BHREJECT: puts("'badheader': FALSE,"); break; |
| 318 |
case BHACCEPT: puts("'badheader': TRUE,"); break; |
| 319 |
} |
| 320 |
|
| 321 |
indent(0); |
| 322 |
fputs("'users': ", stdout); |
| 323 |
indent('['); |
| 324 |
} |
| 325 |
|
| 326 |
indent('{'); |
| 327 |
|
| 328 |
stringdump("remote", ctl->remotename); |
| 329 |
stringdump("password", ctl->password); |
| 330 |
|
| 331 |
indent('\0'); |
| 332 |
fprintf(stdout, "'localnames':["); |
| 333 |
for (idp = ctl->localnames; idp; idp = idp->next) |
| 334 |
{ |
| 335 |
char namebuf[USERNAMELEN + 1]; |
| 336 |
|
| 337 |
strlcpy(namebuf, visbuf(idp->id), sizeof(namebuf)); |
| 338 |
if (idp->val.id2) |
| 339 |
fprintf(stdout, "(\"%s\", %s)", namebuf, visbuf(idp->val.id2)); |
| 340 |
else |
| 341 |
fprintf(stdout, "\"%s\"", namebuf); |
| 342 |
if (idp->next) |
| 343 |
fputs(", ", stdout); |
| 344 |
} |
| 345 |
if (ctl->wildcard) |
| 346 |
fputs(", '*'", stdout); |
| 347 |
fputs("],\n", stdout); |
| 348 |
|
| 349 |
booldump("fetchall", ctl->fetchall); |
| 350 |
booldump("keep", ctl->keep); |
| 351 |
booldump("flush", ctl->flush); |
| 352 |
booldump("limitflush", ctl->limitflush); |
| 353 |
booldump("rewrite", ctl->rewrite); |
| 354 |
booldump("stripcr", ctl->stripcr); |
| 355 |
booldump("forcecr", ctl->forcecr); |
| 356 |
booldump("pass8bits", ctl->pass8bits); |
| 357 |
booldump("dropstatus", ctl->dropstatus); |
| 358 |
booldump("dropdelivered", ctl->dropdelivered); |
| 359 |
booldump("mimedecode", ctl->mimedecode); |
| 360 |
booldump("idle", ctl->idle); |
| 361 |
|
| 362 |
stringdump("mda", ctl->mda); |
| 363 |
stringdump("bsmtp", ctl->bsmtp); |
| 364 |
indent('\0'); |
| 365 |
if (ctl->listener == LMTP_MODE) |
| 366 |
fputs("'lmtp':TRUE,\n", stdout); |
| 367 |
else |
| 368 |
fputs("'lmtp':FALSE,\n", stdout); |
| 369 |
|
| 370 |
stringdump("preconnect", ctl->preconnect); |
| 371 |
stringdump("postconnect", ctl->postconnect); |
| 372 |
numdump("limit", ctl->limit); |
| 373 |
numdump("warnings", ctl->warnings); |
| 374 |
numdump("fetchlimit", ctl->fetchlimit); |
| 375 |
numdump("fetchsizelimit", ctl->fetchsizelimit); |
| 376 |
numdump("fastuidl", ctl->fastuidl); |
| 377 |
numdump("batchlimit", ctl->batchlimit); |
| 378 |
#ifdef SSL_ENABLE |
| 379 |
booldump("ssl", ctl->use_ssl); |
| 380 |
stringdump("sslkey", ctl->sslkey); |
| 381 |
stringdump("sslcert", ctl->sslcert); |
| 382 |
stringdump("sslproto", ctl->sslproto); |
| 383 |
booldump("sslcertck", ctl->sslcertck); |
| 384 |
stringdump("sslcertpath", ctl->sslcertpath); |
| 385 |
stringdump("sslcommonname", ctl->sslcommonname); |
| 386 |
stringdump("sslfingerprint", ctl->sslfingerprint); |
| 387 |
#endif /* SSL_ENABLE */ |
| 388 |
numdump("expunge", ctl->expunge); |
| 389 |
stringdump("properties", ctl->properties); |
| 390 |
listdump("smtphunt", ctl->smtphunt); |
| 391 |
listdump("fetchdomains", ctl->domainlist); |
| 392 |
stringdump("smtpaddress", ctl->smtpaddress); |
| 393 |
stringdump("smtpname", ctl->smtpname); |
| 394 |
|
| 395 |
indent('\0'); |
| 396 |
fprintf(stdout, "'antispam':'"); |
| 397 |
for (idp = ctl->antispam; idp; idp = idp->next) |
| 398 |
{ |
| 399 |
fprintf(stdout, "%d", idp->val.status.num); |
| 400 |
if (idp->next) |
| 401 |
fputs(" ", stdout); |
| 402 |
} |
| 403 |
fputs("',\n", stdout); |
| 404 |
listdump("mailboxes", ctl->mailboxes); |
| 405 |
|
| 406 |
indent('}'); |
| 407 |
indent('\0'); |
| 408 |
fputc(',', stdout); |
| 409 |
} |
| 410 |
|
| 411 |
/* end last span of user entries and last server entry */ |
| 412 |
indent(']'); |
| 413 |
indent('}'); |
| 414 |
|
| 415 |
/* end array of servers */ |
| 416 |
indent(']'); |
| 417 |
|
| 418 |
alldone: |
| 419 |
/* end top-level dictionary */ |
| 420 |
indent('}'); |
| 421 |
fputs("# End of initializer\n", stdout); |
| 422 |
} |
| 423 |
|
| 424 |
/* conf.c ends here */ |