Fossil

Check-in [775e529b]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Add the "fossil email inbound" command, though it currently does not analyze the inbound emails - it just stores the emails in a directory for later human viewing.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | email-alerts
Files: files | file ages | folders
SHA3-256: 775e529b32022e378b4d0abd30f7fb49999af9fb1e041f79789ef2084dcbb316
User & Date: drh 2018-06-21 23:01:37.921
Context
2018-06-22
01:18
Rename the email_pending table to pending_alert. Add triggers to fill in the pending_alert table each time a row is added to the event table. ... (check-in: 8c4b92ad user: drh tags: email-alerts)
2018-06-21
23:01
Add the "fossil email inbound" command, though it currently does not analyze the inbound emails - it just stores the emails in a directory for later human viewing. ... (check-in: 775e529b user: drh tags: email-alerts)
22:37
Continuing refinement of the web pages for handling email subscriptions. ... (check-in: 84d0d853 user: drh tags: email-alerts)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/email.c.
176
177
178
179
180
181
182









183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201













202
203
204
205
206
207
208

  entry_attribute("Administrator email address", 40, "email-admin",
                   "eadmin", "", 0);
  @ <p>This is the email for the human administrator for the system.
  @ Abuse and trouble reports are send here.
  @ (Property: "email-admin")</p>
  @ <hr>









  @ <p><input type="submit"  name="submit" value="Apply Changes" /></p>
  @ </div></form>
  db_end_transaction(0);
  style_footer();
}

/*
** Encode pMsg as MIME base64 and append it to pOut
*/
static void append_base64(Blob *pOut, Blob *pMsg){
  int n, i, k;
  char zBuf[100];
  n = blob_size(pMsg);
  for(i=0; i<n; i+=54){
    k = translateBase64(blob_buffer(pMsg)+i, i+54<n ? 54 : n-i, zBuf);
    blob_append(pOut, zBuf, k);
    blob_append(pOut, "\r\n", 2);
  }
}














#if defined(_WIN32) || defined(WIN32)
# undef popen
# define popen _popen
# undef pclose
# define pclose _pclose
#endif







>
>
>
>
>
>
>
>
>



















>
>
>
>
>
>
>
>
>
>
>
>
>







176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230

  entry_attribute("Administrator email address", 40, "email-admin",
                   "eadmin", "", 0);
  @ <p>This is the email for the human administrator for the system.
  @ Abuse and trouble reports are send here.
  @ (Property: "email-admin")</p>
  @ <hr>

  entry_attribute("Inbound email directory", 40, "email-receive-dir",
                   "erdir", "", 0);
  @ <p>Inbound emails can be stored in a directory for analysis as
  @ a debugging aid.  Put the name of that directory in this entry box.
  @ Disable saving of inbound email by making this an empty string.
  @ Abuse and trouble reports are send here.
  @ (Property: "email-receive-dir")</p>
  @ <hr>
  @ <p><input type="submit"  name="submit" value="Apply Changes" /></p>
  @ </div></form>
  db_end_transaction(0);
  style_footer();
}

/*
** Encode pMsg as MIME base64 and append it to pOut
*/
static void append_base64(Blob *pOut, Blob *pMsg){
  int n, i, k;
  char zBuf[100];
  n = blob_size(pMsg);
  for(i=0; i<n; i+=54){
    k = translateBase64(blob_buffer(pMsg)+i, i+54<n ? 54 : n-i, zBuf);
    blob_append(pOut, zBuf, k);
    blob_append(pOut, "\r\n", 2);
  }
}

/*
** Come up with a unique filename in the zDir directory.
**
** Space to hold the filename is obtained from mprintf() and must
** be freed using fossil_free() by the caller.
*/
static char *emailTempFilename(const char *zDir){
  char *zFile = db_text(0,
     "SELECT %Q||strftime('/%%Y%%m%%d%%H%%M%%S-','now')||hex(randomblob(8))",
        zDir);
  return zFile;
}

#if defined(_WIN32) || defined(WIN32)
# undef popen
# define popen _popen
# undef pclose
# define pclose _pclose
#endif
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320














321
322
323
324
325
326
327
      if( out ){
        fwrite(blob_buffer(&all), 1, blob_size(&all), out);
        fclose(out);
      }
    }
  }else if( strcmp(zDest, "dir")==0 ){
    const char *zDir = db_get("email-send-dir","./");
    char *zFile = db_text(0,
        "SELECT %Q||strftime('/%%Y%%m%%d%%H%%M%%S','now')||hex(randomblob(8))",
        zDir);
    blob_write_to_file(&all, zFile);
    fossil_free(zFile);
  }else if( strcmp(zDest, "stdout")==0 ){
    fossil_print("%s\n", blob_str(&all));
  }
  blob_zero(&all);
}















/*
** SETTING: email-send-method         width=5 default=off
** Determine the method used to send email.  Allowed values are
** "off", "pipe", "dir", "db", and "stdout".  The "off" value means
** no email is ever sent.  The "pipe" value means email messages are
** piped into a command determined by the email-send-command setting.







|
<
<







>
>
>
>
>
>
>
>
>
>
>
>
>
>







326
327
328
329
330
331
332
333


334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
      if( out ){
        fwrite(blob_buffer(&all), 1, blob_size(&all), out);
        fclose(out);
      }
    }
  }else if( strcmp(zDest, "dir")==0 ){
    const char *zDir = db_get("email-send-dir","./");
    char *zFile = emailTempFilename(zDir);


    blob_write_to_file(&all, zFile);
    fossil_free(zFile);
  }else if( strcmp(zDest, "stdout")==0 ){
    fossil_print("%s\n", blob_str(&all));
  }
  blob_zero(&all);
}

/*
** Analyze and act on a received email.
**
** This routine takes ownership of the Blob parameter and is responsible
** for freeing that blob when it is done with it.
**
** This routine acts on all email messages received from the
** "fossil email inbound" command.
*/
void email_receive(Blob *pMsg){
  /* To Do:  Look for bounce messages and possibly disable subscriptions */
  blob_zero(pMsg);
}

/*
** SETTING: email-send-method         width=5 default=off
** Determine the method used to send email.  Allowed values are
** "off", "pipe", "dir", "db", and "stdout".  The "off" value means
** no email is ever sent.  The "pipe" value means email messages are
** piped into a command determined by the email-send-command setting.
349
350
351
352
353
354
355






356
357
358
359
360
361
362
363




364
365
366
367
368
369
370
** if the email-send-method is set to "db".
*/
/*
** SETTING: email-self               width=40
** This is the email address for the repository.  Outbound emails add
** this email address as the "From:" field.
*/








/*
** COMMAND: email
** 
** Usage: %fossil email SUBCOMMAND ARGS...
**
** Subcommands:




**
**    reset                   Hard reset of all email notification tables
**                            in the repository.  This erases all subscription
**                            information.  Use with extreme care.
**
**    send TO [OPTIONS]       Send a single email message using whatever
**                            email sending mechanism is currently configured.







>
>
>
>
>
>








>
>
>
>







383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
** if the email-send-method is set to "db".
*/
/*
** SETTING: email-self               width=40
** This is the email address for the repository.  Outbound emails add
** this email address as the "From:" field.
*/
/*
** SETTING: email-receive-dir         width=40
** Inbound email messages are saved as separate files in this directory,
** for debugging analysis.  Disable saving of inbound emails omitting
** this setting, or making it an empty string.
*/


/*
** COMMAND: email
** 
** Usage: %fossil email SUBCOMMAND ARGS...
**
** Subcommands:
**
**    inbound [FILE]          Receive an inbound email message.  This message
**                            is analyzed to see if it is a bounce, and if
**                            necessary, subscribers may be disabled.
**
**    reset                   Hard reset of all email notification tables
**                            in the repository.  This erases all subscription
**                            information.  Use with extreme care.
**
**    send TO [OPTIONS]       Send a single email message using whatever
**                            email sending mechanism is currently configured.
382
383
384
385
386
387
388















389
390
391
392
393
394
395
void email_cmd(void){
  const char *zCmd;
  int nCmd;
  db_find_and_open_repository(0, 0);
  email_schema();
  zCmd = g.argc>=3 ? g.argv[2] : "x";
  nCmd = (int)strlen(zCmd);















  if( strncmp(zCmd, "reset", nCmd)==0 ){
    Blob yn;
    int c;
    fossil_print(
        "This will erase all content in the repository tables, thus\n"
        "deleting all subscriber information.  The information will be\n"
        "unrecoverable.\n");







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
void email_cmd(void){
  const char *zCmd;
  int nCmd;
  db_find_and_open_repository(0, 0);
  email_schema();
  zCmd = g.argc>=3 ? g.argv[2] : "x";
  nCmd = (int)strlen(zCmd);
  if( strncmp(zCmd, "inbound", nCmd)==0 ){
    Blob email;
    const char *zInboundDir = db_get("email-receive-dir","");
    verify_all_options();
    if( g.argc!=3 && g.argc!=4 ){
      usage("inbound [FILE]");
    }
    blob_read_from_file(&email, g.argc==3 ? "-" : g.argv[3], ExtFILE);
    if( zInboundDir[0] ){
      char *zFN = emailTempFilename(zInboundDir);
      blob_write_to_file(&email, zFN);
      fossil_free(zFN);
    }
    email_receive(&email);
  }else
  if( strncmp(zCmd, "reset", nCmd)==0 ){
    Blob yn;
    int c;
    fossil_print(
        "This will erase all content in the repository tables, thus\n"
        "deleting all subscriber information.  The information will be\n"
        "unrecoverable.\n");
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
    pSetting = setting_info(&nSetting);
    for(; nSetting>0; nSetting--, pSetting++ ){
      if( strncmp(pSetting->name,"email-",6)!=0 ) continue;
      print_setting(pSetting);
    }
  }
  else{
    usage("reset|send|setting");
  }
}

/*
** Do error checking on a submitted subscription form.  Return TRUE
** if the submission is valid.  Return false if any problems are seen.
*/







|







523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
    pSetting = setting_info(&nSetting);
    for(; nSetting>0; nSetting--, pSetting++ ){
      if( strncmp(pSetting->name,"email-",6)!=0 ) continue;
      print_setting(pSetting);
    }
  }
  else{
    usage("inbound|reset|send|setting");
  }
}

/*
** Do error checking on a submitted subscription form.  Return TRUE
** if the submission is valid.  Return false if any problems are seen.
*/