Fossil

Check-in [aa80d694]
Login

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

Overview
Comment:Add a setup menu option for Email-Server. Try to get the build of this branch working (without DNS support) for non-linux systems.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | smtp
Files: files | file ages | folders
SHA3-256: aa80d6941e8e9a53e5d593e36256b92d99a255e3bbd2986ecae37f42252a6642
User & Date: drh 2018-07-11 19:41:52.321
Context
2018-07-11
19:46
Fix the socket_receive() function so that it compiles on systems that lack the MSG_DONTWAIT macro (Windows). Such systems lose non-blocking capabilities, but they work otherwise. ... (Closed-Leaf check-in: 31d274d0 user: drh tags: smtp)
19:41
Add a setup menu option for Email-Server. Try to get the build of this branch working (without DNS support) for non-linux systems. ... (check-in: aa80d694 user: drh tags: smtp)
15:02
Merge changes from trunk. ... (check-in: cde5b96d user: drh tags: smtp)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/email.c.
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
      style_submenu_element("Add New Subscriber","%R/subscribe");
    }
  }
}


/*
** WEBPAGE: setup_email
**
** Administrative page for configuring and controlling email notification.
** Normally accessible via the /Admin/Email menu.
*/
void setup_email(void){
  static const char *const azSendMethods[] = {
    "off",   "Disabled",
    "pipe",  "Pipe to a command",
    "db",    "Store in a database",
    "dir",   "Store in a directory",
    "relay", "SMTP relay"
  };
  login_check_credentials();
  if( !g.perm.Setup ){
    login_needed(0);
    return;
  }
  db_begin_transaction();

  email_submenu_common();
  style_header("Email Notification Setup");
  @ <form action="%R/setup_email" method="post"><div>
  @ <input type="submit"  name="submit" value="Apply Changes" /><hr>
  login_insert_csrf_secret();

  entry_attribute("Canonical Server URL", 40, "email-url",
                   "eurl", "", 0);
  @ <p><b>Required.</b>
  @ This is URL used as the basename for hyperlinks included in







|


|

|
















|







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
      style_submenu_element("Add New Subscriber","%R/subscribe");
    }
  }
}


/*
** WEBPAGE: setup_notification
**
** Administrative page for configuring and controlling email notification.
** Normally accessible via the /Admin/Notification menu.
*/
void setup_notification(void){
  static const char *const azSendMethods[] = {
    "off",   "Disabled",
    "pipe",  "Pipe to a command",
    "db",    "Store in a database",
    "dir",   "Store in a directory",
    "relay", "SMTP relay"
  };
  login_check_credentials();
  if( !g.perm.Setup ){
    login_needed(0);
    return;
  }
  db_begin_transaction();

  email_submenu_common();
  style_header("Email Notification Setup");
  @ <form action="%R/setup_notification" method="post"><div>
  @ <input type="submit"  name="submit" value="Apply Changes" /><hr>
  login_insert_csrf_secret();

  entry_attribute("Canonical Server URL", 40, "email-url",
                   "eurl", "", 0);
  @ <p><b>Required.</b>
  @ This is URL used as the basename for hyperlinks included in
Changes to src/setup.c.
112
113
114
115
116
117
118


119

120
121
122
123
124
125
126
    " on the same server");
  setup_menu_entry("Tickets", "tktsetup",
    "Configure the trouble-ticketing system for this repository");
  setup_menu_entry("Search","srchsetup",
    "Configure the built-in search engine");
  setup_menu_entry("URL Aliases", "waliassetup",
    "Configure URL aliases");


  setup_menu_entry("Email", "setup_email", "Email notifications");

  setup_menu_entry("Transfers", "xfersetup",
    "Configure the transfer system for this repository");
  setup_menu_entry("Skins", "setup_skin",
    "Select and/or modify the web interface \"skins\"");
  setup_menu_entry("Moderation", "setup_modreq",
    "Enable/Disable requiring moderator approval of Wiki and/or Ticket"
    " changes and attachments.");







>
>
|
>







112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
    " on the same server");
  setup_menu_entry("Tickets", "tktsetup",
    "Configure the trouble-ticketing system for this repository");
  setup_menu_entry("Search","srchsetup",
    "Configure the built-in search engine");
  setup_menu_entry("URL Aliases", "waliassetup",
    "Configure URL aliases");
  setup_menu_entry("Notification", "setup_notification",
    "Automatic notifications of changes via outbound email");
  setup_menu_entry("Email-Server", "setup_smtp",
    "Activate and configure the built-in email server");
  setup_menu_entry("Transfers", "xfersetup",
    "Configure the transfer system for this repository");
  setup_menu_entry("Skins", "setup_skin",
    "Select and/or modify the web interface \"skins\"");
  setup_menu_entry("Moderation", "setup_modreq",
    "Enable/Disable requiring moderator approval of Wiki and/or Ticket"
    " changes and attachments.");
Changes to src/smtp.c.
18
19
20
21
22
23
24



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
** Implementation of SMTP (Simple Mail Transport Protocol) according
** to RFC 5321.
*/
#include "config.h"
#include "smtp.h"
#include <assert.h>





#if !defined(FOSSIL_OMIT_SMTP)
#if defined(_WIN32)
   /* Don't yet know how to do this on windows */
#else
#  include <sys/types.h>
#  include <netinet/in.h>
#  include <arpa/nameser.h>
#  include <resolv.h>
#endif
#endif /* !defined(FOSSIL_OMIT_SMTP) */


/*
** Find the hostname for receiving email for the domain given
** in zDomain.  Return NULL if not found or not implemented.
** If multiple email receivers are advertized, pick the one with
** the lowest preference number.
**
** The returned string is obtained from fossil_malloc()
** and should be released using fossil_free().
*/
char *smtp_mx_host(const char *zDomain){
#if !defined(_WIN32) && !defined(FOSSIL_OMIT_SMTP)
  int nDns;                       /* Length of the DNS reply */
  int rc;                         /* Return code from various APIs */
  int i;                          /* Loop counter */
  int iBestPriority = 9999999;    /* Best priority */
  int nRec;                       /* Number of answers */
  ns_msg h;                       /* DNS reply parser */
  const unsigned char *pBest = 0; /* RDATA for the best answer */







>
>
>

<
|
<
<




|
<












|







18
19
20
21
22
23
24
25
26
27
28

29


30
31
32
33
34

35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
** Implementation of SMTP (Simple Mail Transport Protocol) according
** to RFC 5321.
*/
#include "config.h"
#include "smtp.h"
#include <assert.h>

#ifdef __linux__
# define FOSSIL_ENABLE_DNS_LOOKUP
#endif


#if defined(FOSSIL_ENABLE_DNS_LOOKUP)


#  include <sys/types.h>
#  include <netinet/in.h>
#  include <arpa/nameser.h>
#  include <resolv.h>
#endif /* defined(FOSSIL_ENABLE_DNS_LOOKUP) */



/*
** Find the hostname for receiving email for the domain given
** in zDomain.  Return NULL if not found or not implemented.
** If multiple email receivers are advertized, pick the one with
** the lowest preference number.
**
** The returned string is obtained from fossil_malloc()
** and should be released using fossil_free().
*/
char *smtp_mx_host(const char *zDomain){
#if defined(FOSSIL_ENABLE_DNS_LOOKUP)
  int nDns;                       /* Length of the DNS reply */
  int rc;                         /* Return code from various APIs */
  int i;                          /* Loop counter */
  int iBestPriority = 9999999;    /* Best priority */
  int nRec;                       /* Number of answers */
  ns_msg h;                       /* DNS reply parser */
  const unsigned char *pBest = 0; /* RDATA for the best answer */
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
    }
  }
  if( pBest ){
    ns_name_uncompress(aDns, aDns+nDns, pBest+2,
                       zHostname, sizeof(zHostname));
    return fossil_strdup(zHostname);
  }
#endif /* not windows */
  return 0;
}

/*
** COMMAND: test-find-mx
**
** Usage: %fossil test-find-mx DOMAIN ...







|







78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
    }
  }
  if( pBest ){
    ns_name_uncompress(aDns, aDns+nDns, pBest+2,
                       zHostname, sizeof(zHostname));
    return fossil_strdup(zHostname);
  }
#endif /* defined(FOSSIL_ENABLE_DNS_LOOKUP) */
  return 0;
}

/*
** COMMAND: test-find-mx
**
** Usage: %fossil test-find-mx DOMAIN ...
668
669
670
671
672
673
674



















675
676
677
678
679
680
681
  if( eForce==2 ){
    db_multi_exec(zEmailDrop/*works-like:""*/);
  }
  if( eForce==1 || !db_table_exists("repository","emailblob") ){
    db_multi_exec(zEmailSchema/*works-like:""*/);
  }
}




















#if LOCAL_INTERFACE
/*
** State information for the server
*/
struct SmtpServer {
  sqlite3_int64 idTranscript; /* Transcript ID number */







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







667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
  if( eForce==2 ){
    db_multi_exec(zEmailDrop/*works-like:""*/);
  }
  if( eForce==1 || !db_table_exists("repository","emailblob") ){
    db_multi_exec(zEmailSchema/*works-like:""*/);
  }
}

/*
** WEBPAGE: setup_smtp
**
** Administrative page for configuring and controlling inbound email and
** output email queuing.  This page is available to administrators
** only via the /Admin/EmailServer menu.
*/
void setup_smtp(void){
  login_check_credentials();
  if( !g.perm.Setup ){
    login_needed(0);
    return;
  }
  style_header("Email Server Setup");
  @ <i>Pending...</i>
  style_footer();
}


#if LOCAL_INTERFACE
/*
** State information for the server
*/
struct SmtpServer {
  sqlite3_int64 idTranscript; /* Transcript ID number */
Changes to src/webmail.c.
32
33
34
35
36
37
38

39
40
41
42
43
44
45
** This page can be used to read content from the EMAILBOX table
** that contains email received by the "fossil smtpd" command.
*/
void webmail_page(void){
  int emailid;
  Stmt q;
  Blob sql;

  login_check_credentials();
  if( g.zLogin==0 ){
    login_needed(0);
    return;
  }
  if( !db_table_exists("repository","emailbox") ){
    style_header("Webmail Not Available");







>







32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
** This page can be used to read content from the EMAILBOX table
** that contains email received by the "fossil smtpd" command.
*/
void webmail_page(void){
  int emailid;
  Stmt q;
  Blob sql;
  int showAll = 0;
  login_check_credentials();
  if( g.zLogin==0 ){
    login_needed(0);
    return;
  }
  if( !db_table_exists("repository","emailbox") ){
    style_header("Webmail Not Available");
68
69
70
71
72
73
74
75
76
77
78
79













80
81
82
83
84
85
86
87
88
89
90
91




92
93
94
95
96
97
98
      return;
    }
    db_finalize(&q);
  }
  style_header("Webmail");
  blob_init(&sql, 0, 0);
  blob_append_sql(&sql,
        /*    0       1                           2        3        4  */
    "SELECT efrom, datetime(edate,'unixepoch'), estate, esubject, emsgid"
    " FROM emailbox"
  );
  if( !g.perm.Admin || P("all")==0 ){













    blob_append_sql(&sql, " WHERE euser=%Q", g.zLogin);
  }
  blob_append_sql(&sql, " ORDER BY edate DESC limit 50");
  db_prepare_blob(&q, &sql);
  blob_reset(&sql);
  @ <ol>
  while( db_step(&q)==SQLITE_ROW ){
    int emailid = db_column_int(&q,4);
    const char *zFrom = db_column_text(&q, 0);
    const char *zDate = db_column_text(&q, 1);
    const char *zSubject = db_column_text(&q, 3);
    @ <li>




    @ <a href="%R/webmail?id=%d(emailid)">%h(zFrom) &rarr; %h(zSubject)</a>
    @ %h(zDate)
  }
  db_finalize(&q);
  @ </ol>
  style_footer(); 
}







|
|


|
>
>
>
>
>
>
>
>
>
>
>
>
>












>
>
>
>







69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
      return;
    }
    db_finalize(&q);
  }
  style_header("Webmail");
  blob_init(&sql, 0, 0);
  blob_append_sql(&sql,
        /*    0       1                           2        3        4      5 */
    "SELECT efrom, datetime(edate,'unixepoch'), estate, esubject, emsgid, euser"
    " FROM emailbox"
  );
  if( g.perm.Admin ){
    const char *zUser = P("user");
    if( P("all")!=0 ){
      /* Show all email messages */
      showAll = 1;
    }else{
      style_submenu_element("All", "%R/webmail?all");
      if( zUser ){
        blob_append_sql(&sql, " WHERE euser=%Q", zUser);
      }else{
        blob_append_sql(&sql, " WHERE euser=%Q", g.zLogin);
      }
    }
  }else{
    blob_append_sql(&sql, " WHERE euser=%Q", g.zLogin);
  }
  blob_append_sql(&sql, " ORDER BY edate DESC limit 50");
  db_prepare_blob(&q, &sql);
  blob_reset(&sql);
  @ <ol>
  while( db_step(&q)==SQLITE_ROW ){
    int emailid = db_column_int(&q,4);
    const char *zFrom = db_column_text(&q, 0);
    const char *zDate = db_column_text(&q, 1);
    const char *zSubject = db_column_text(&q, 3);
    @ <li>
    if( showAll ){
      const char *zTo = db_column_text(&q,5);
      @ <a href="%R/webmail?user=%t(zTo)">%h(zTo)</a>:
    }
    @ <a href="%R/webmail?id=%d(emailid)">%h(zFrom) &rarr; %h(zSubject)</a>
    @ %h(zDate)
  }
  db_finalize(&q);
  @ </ol>
  style_footer(); 
}