Fossil SCM
Incremental check-in of initial code for client-side SMTP. Does not work.
Commit
20006a866c8dbb59ba596f1ea31e62803847bb63cb2dddbe14dd0810efa4f0f6
Parent
8f6f25f12dae5bc…
2 files changed
+4
-2
+223
+4
-2
| --- src/http_socket.c | ||
| +++ src/http_socket.c | ||
| @@ -79,12 +79,14 @@ | ||
| 79 | 79 | } |
| 80 | 80 | |
| 81 | 81 | /* |
| 82 | 82 | ** Return the current socket error message |
| 83 | 83 | */ |
| 84 | -const char *socket_errmsg(void){ | |
| 85 | - return socketErrMsg; | |
| 84 | +char *socket_errmsg(void){ | |
| 85 | + char *zResult = socketErrMsg; | |
| 86 | + socketErrMsg = 0; | |
| 87 | + return zResult; | |
| 86 | 88 | } |
| 87 | 89 | |
| 88 | 90 | /* |
| 89 | 91 | ** Call this routine once before any other use of the socket interface. |
| 90 | 92 | ** This routine does initial configuration of the socket module. |
| 91 | 93 |
| --- src/http_socket.c | |
| +++ src/http_socket.c | |
| @@ -79,12 +79,14 @@ | |
| 79 | } |
| 80 | |
| 81 | /* |
| 82 | ** Return the current socket error message |
| 83 | */ |
| 84 | const char *socket_errmsg(void){ |
| 85 | return socketErrMsg; |
| 86 | } |
| 87 | |
| 88 | /* |
| 89 | ** Call this routine once before any other use of the socket interface. |
| 90 | ** This routine does initial configuration of the socket module. |
| 91 |
| --- src/http_socket.c | |
| +++ src/http_socket.c | |
| @@ -79,12 +79,14 @@ | |
| 79 | } |
| 80 | |
| 81 | /* |
| 82 | ** Return the current socket error message |
| 83 | */ |
| 84 | char *socket_errmsg(void){ |
| 85 | char *zResult = socketErrMsg; |
| 86 | socketErrMsg = 0; |
| 87 | return zResult; |
| 88 | } |
| 89 | |
| 90 | /* |
| 91 | ** Call this routine once before any other use of the socket interface. |
| 92 | ** This routine does initial configuration of the socket module. |
| 93 |
+223
| --- src/smtp.c | ||
| +++ src/smtp.c | ||
| @@ -104,5 +104,228 @@ | ||
| 104 | 104 | char *z = smtp_mx_host(g.argv[i]); |
| 105 | 105 | fossil_print("%s: %s\n", g.argv[i], z); |
| 106 | 106 | fossil_free(z); |
| 107 | 107 | } |
| 108 | 108 | } |
| 109 | + | |
| 110 | +#if INTERFACE | |
| 111 | +/* | |
| 112 | +** Information about a single SMTP connection. | |
| 113 | +*/ | |
| 114 | +struct SmtpSession { | |
| 115 | + const char *zFrom; /* Domain from which we are sending */ | |
| 116 | + const char *zDest; /* Domain that will receive the email */ | |
| 117 | + char *zHostname; /* Hostname of SMTP server for zDest */ | |
| 118 | + u32 smtpFlags; /* Flags changing the operation */ | |
| 119 | + FILE *logFile; /* Write session transcript to this log file */ | |
| 120 | + Blob *pTranscript; /* Record session transcript here */ | |
| 121 | + const char *zLabel; /* Either "CS" or "SC" */ | |
| 122 | + char *zErr; /* Error message */ | |
| 123 | +}; | |
| 124 | + | |
| 125 | +/* Allowed values for SmtpSession.smtpFlags */ | |
| 126 | +#define SMTP_TRACE_STDOUT 0x00001 /* Debugging info to console */ | |
| 127 | +#define SMTP_TRACE_FILE 0x00002 /* Debugging info to logFile */ | |
| 128 | +#define SMTP_TRACE_BLOB 0x00004 /* Record transcript */ | |
| 129 | + | |
| 130 | +#endif | |
| 131 | + | |
| 132 | +/* | |
| 133 | +** Shutdown an SmtpSession | |
| 134 | +*/ | |
| 135 | +void smtp_session_free(SmtpSession *pSession){ | |
| 136 | + socket_close(); | |
| 137 | + fossil_free(pSession->zHostname); | |
| 138 | + fossil_free(pSession->zErr); | |
| 139 | + fossil_free(pSession); | |
| 140 | +} | |
| 141 | + | |
| 142 | +/* | |
| 143 | +** Allocate a new SmtpSession object. | |
| 144 | +** | |
| 145 | +** Both zFrom and zDest must be specified for a client side SMTP connection. | |
| 146 | +** For a server-side, specify only zFrom. | |
| 147 | +*/ | |
| 148 | +SmtpSession *smtp_session_new( | |
| 149 | + const char *zFrom, /* Domain name of our end. */ | |
| 150 | + const char *zDest, /* Domain of the other end. */ | |
| 151 | + u32 smtpFlags, /* Flags */ | |
| 152 | + ... /* Arguments depending on the flags */ | |
| 153 | +){ | |
| 154 | + SmtpSession *p; | |
| 155 | + va_list ap; | |
| 156 | + UrlData url; | |
| 157 | + | |
| 158 | + p = fossil_malloc( sizeof(*p) ); | |
| 159 | + memset(p, 0, sizeof(*p)); | |
| 160 | + p->zFrom = zFrom; | |
| 161 | + p->zDest = zDest; | |
| 162 | + p->zLabel = zDest==0 ? "CS" : "SC"; | |
| 163 | + p->smtpFlags = smtpFlags; | |
| 164 | + va_start(ap, smtpFlags); | |
| 165 | + if( smtpFlags & SMTP_TRACE_FILE ){ | |
| 166 | + p->logFile = va_arg(ap, FILE*); | |
| 167 | + }else if( smtpFlags & SMTP_TRACE_BLOB ){ | |
| 168 | + p->pTranscript = va_arg(ap, Blob*); | |
| 169 | + } | |
| 170 | + va_end(ap); | |
| 171 | + p->zHostname = smtp_mx_host(zDest); | |
| 172 | + if( p->zHostname==0 ){ | |
| 173 | + p->zErr = mprintf("cannot locate SMTP server for \"%s\"", zDest); | |
| 174 | + return p; | |
| 175 | + } | |
| 176 | + memset(&url, 0, sizeof(url)); | |
| 177 | + url.name = p->zHostname; | |
| 178 | + url.port = 25; | |
| 179 | + socket_global_init(); | |
| 180 | + if( socket_open(&url) ){ | |
| 181 | + p->zErr = socket_errmsg(); | |
| 182 | + socket_close(); | |
| 183 | + } | |
| 184 | + return p; | |
| 185 | +} | |
| 186 | + | |
| 187 | +/* | |
| 188 | +** Send a single line of output the SMTP client to the server. | |
| 189 | +*/ | |
| 190 | +static void smtp_send_line(SmtpSession *p, const char *zFormat, ...){ | |
| 191 | + Blob b = empty_blob; | |
| 192 | + va_list ap; | |
| 193 | + char *z; | |
| 194 | + int n; | |
| 195 | + va_start(ap, zFormat); | |
| 196 | + blob_vappendf(&b, zFormat, ap); | |
| 197 | + va_end(ap); | |
| 198 | + z = blob_buffer(&b); | |
| 199 | + n = blob_size(&b); | |
| 200 | + assert( n>=2 ); | |
| 201 | + assert( z[n-1]=='\n' ); | |
| 202 | + assert( z[n-2]=='\r' ); | |
| 203 | + if( p->smtpFlags & SMTP_TRACE_STDOUT ){ | |
| 204 | + fossil_print("%c: %.*s\n", p->zLabel[1], n-2, z); | |
| 205 | + } | |
| 206 | + if( p->smtpFlags & SMTP_TRACE_FILE ){ | |
| 207 | + fprintf(p->logFile, "%c: %.*s\n", p->zLabel[1], n-2, z); | |
| 208 | + } | |
| 209 | + if( p->smtpFlags & SMTP_TRACE_BLOB ){ | |
| 210 | + blob_appendf(p->pTranscript, "%c: %.*s\n", p->zLabel[1], n-2, z); | |
| 211 | + } | |
| 212 | + socket_send(0, z, n); | |
| 213 | + blob_zero(&b); | |
| 214 | +} | |
| 215 | + | |
| 216 | +/* | |
| 217 | +** Read a line of input received from the SMTP server. Append | |
| 218 | +** the received line onto the end of the blob. | |
| 219 | +*/ | |
| 220 | +static void smtp_recv_line(SmtpSession *p, Blob *in){ | |
| 221 | + int n = blob_size(in); | |
| 222 | + int iStart = n; | |
| 223 | + char *z; | |
| 224 | + do{ | |
| 225 | + size_t got; | |
| 226 | + blob_resize(in, n+1000); | |
| 227 | + z = blob_buffer(in); | |
| 228 | + got = socket_receive(0, z+n, 1000); | |
| 229 | + in->nUsed += got; | |
| 230 | + n += got; | |
| 231 | + }while( n<1 || z[n-1]!='\n' ); | |
| 232 | + z = blob_buffer(in) + iStart; | |
| 233 | + n = blob_size(in) - iStart - 1; | |
| 234 | + if( n && z[n-1]=='\r' ) n--; | |
| 235 | + if( p->smtpFlags & SMTP_TRACE_STDOUT ){ | |
| 236 | + fossil_print("%c: %.*s\n", p->zLabel[0], n, z); | |
| 237 | + } | |
| 238 | + if( p->smtpFlags & SMTP_TRACE_FILE ){ | |
| 239 | + fprintf(p->logFile, "%c: %.*s\n", p->zLabel[0], n, z); | |
| 240 | + } | |
| 241 | + if( p->smtpFlags & SMTP_TRACE_BLOB ){ | |
| 242 | + blob_appendf(p->pTranscript, "%c: %.*s\n", p->zLabel[0], n-2, z); | |
| 243 | + } | |
| 244 | +} | |
| 245 | + | |
| 246 | +/* | |
| 247 | +** Capture a single-line server reply. | |
| 248 | +*/ | |
| 249 | +static void smtp_get_reply_from_server( | |
| 250 | + SmtpSession *p, /* The SMTP connection */ | |
| 251 | + Blob *in, /* Buffer used to hold the reply */ | |
| 252 | + int *piCode, /* The return code */ | |
| 253 | + int *pbMore, /* True if the reply is not complete */ | |
| 254 | + char **pzArg /* Argument */ | |
| 255 | +){ | |
| 256 | + blob_truncate(in, 0); | |
| 257 | + smtp_recv_line(p, in); | |
| 258 | + *piCode = atoi(blob_str(in)); | |
| 259 | + *pbMore = blob_size(in)>=4 && blob_str(in)[3]=='-'; | |
| 260 | + *pzArg = blob_size(in)>=4 ? blob_str(in)+4 : ""; | |
| 261 | +} | |
| 262 | + | |
| 263 | +/* | |
| 264 | +** Have the client send a QUIT message. | |
| 265 | +*/ | |
| 266 | +int smtp_client_quit(SmtpSession *p){ | |
| 267 | + Blob in = BLOB_INITIALIZER; | |
| 268 | + int iCode = 0; | |
| 269 | + int bMore = 0; | |
| 270 | + char *zArg = 0; | |
| 271 | + smtp_send_line(p, "QUIT\r\n"); | |
| 272 | + do{ | |
| 273 | + smtp_get_reply_from_server(p, &in, &iCode, &bMore, &zArg); | |
| 274 | + }while( bMore ); | |
| 275 | + socket_close(); | |
| 276 | + return 0; | |
| 277 | +} | |
| 278 | + | |
| 279 | +/* | |
| 280 | +** Begin a client SMTP session. Wait for the initial 220 then send | |
| 281 | +** the EHLO and wait for a 250. | |
| 282 | +** | |
| 283 | +** Return 0 on success and non-zero for a failure. | |
| 284 | +*/ | |
| 285 | +int smtp_client_startup(SmtpSession *p){ | |
| 286 | + Blob in = BLOB_INITIALIZER; | |
| 287 | + int iCode = 0; | |
| 288 | + int bMore = 0; | |
| 289 | + char *zArg = 0; | |
| 290 | + do{ | |
| 291 | + smtp_get_reply_from_server(p, &in, &iCode, &bMore, &zArg); | |
| 292 | + }while( bMore ); | |
| 293 | + if( iCode!=220 ){ | |
| 294 | + smtp_client_quit(p); | |
| 295 | + return 1; | |
| 296 | + } | |
| 297 | + smtp_send_line(p, "EHLO %s\r\n", p->zFrom); | |
| 298 | + do{ | |
| 299 | + smtp_get_reply_from_server(p, &in, &iCode, &bMore, &zArg); | |
| 300 | + }while( bMore ); | |
| 301 | + if( iCode!=250 ){ | |
| 302 | + smtp_client_quit(p); | |
| 303 | + return 1; | |
| 304 | + } | |
| 305 | + return 0; | |
| 306 | +} | |
| 307 | + | |
| 308 | +/* | |
| 309 | +** COMMAND: test-smtp-probe | |
| 310 | +** | |
| 311 | +** Usage: %fossil test-smtp-probe DOMAIN ME | |
| 312 | +** | |
| 313 | +** Interact with the SMTP server for DOMAIN by setting up a connection | |
| 314 | +** and then immediately shutting it back down. Log all interaction | |
| 315 | +** on the console. Use ME as the domain name of the sender. | |
| 316 | +*/ | |
| 317 | +void test_smtp_probe(void){ | |
| 318 | + char *zHost; | |
| 319 | + SmtpSession *p; | |
| 320 | + int rc; | |
| 321 | + if( g.argc!=4 ) usage("DOMAIN ME"); | |
| 322 | + zHost = smtp_mx_host(g.argv[2]); | |
| 323 | + if( zHost==0 ){ | |
| 324 | + fossil_fatal("cannot resolve the MX for \"%s\"", g.argv[2]); | |
| 325 | + } | |
| 326 | + fossil_print("Contacting host \"%s\"\n", zHost); | |
| 327 | + p = smtp_session_new(g.argv[3], zHost, SMTP_TRACE_STDOUT); | |
| 328 | + rc = smtp_client_startup(p); | |
| 329 | + if( !rc ) smtp_client_quit(p); | |
| 330 | + smtp_session_free(p); | |
| 331 | +} | |
| 109 | 332 |
| --- src/smtp.c | |
| +++ src/smtp.c | |
| @@ -104,5 +104,228 @@ | |
| 104 | char *z = smtp_mx_host(g.argv[i]); |
| 105 | fossil_print("%s: %s\n", g.argv[i], z); |
| 106 | fossil_free(z); |
| 107 | } |
| 108 | } |
| 109 |
| --- src/smtp.c | |
| +++ src/smtp.c | |
| @@ -104,5 +104,228 @@ | |
| 104 | char *z = smtp_mx_host(g.argv[i]); |
| 105 | fossil_print("%s: %s\n", g.argv[i], z); |
| 106 | fossil_free(z); |
| 107 | } |
| 108 | } |
| 109 | |
| 110 | #if INTERFACE |
| 111 | /* |
| 112 | ** Information about a single SMTP connection. |
| 113 | */ |
| 114 | struct SmtpSession { |
| 115 | const char *zFrom; /* Domain from which we are sending */ |
| 116 | const char *zDest; /* Domain that will receive the email */ |
| 117 | char *zHostname; /* Hostname of SMTP server for zDest */ |
| 118 | u32 smtpFlags; /* Flags changing the operation */ |
| 119 | FILE *logFile; /* Write session transcript to this log file */ |
| 120 | Blob *pTranscript; /* Record session transcript here */ |
| 121 | const char *zLabel; /* Either "CS" or "SC" */ |
| 122 | char *zErr; /* Error message */ |
| 123 | }; |
| 124 | |
| 125 | /* Allowed values for SmtpSession.smtpFlags */ |
| 126 | #define SMTP_TRACE_STDOUT 0x00001 /* Debugging info to console */ |
| 127 | #define SMTP_TRACE_FILE 0x00002 /* Debugging info to logFile */ |
| 128 | #define SMTP_TRACE_BLOB 0x00004 /* Record transcript */ |
| 129 | |
| 130 | #endif |
| 131 | |
| 132 | /* |
| 133 | ** Shutdown an SmtpSession |
| 134 | */ |
| 135 | void smtp_session_free(SmtpSession *pSession){ |
| 136 | socket_close(); |
| 137 | fossil_free(pSession->zHostname); |
| 138 | fossil_free(pSession->zErr); |
| 139 | fossil_free(pSession); |
| 140 | } |
| 141 | |
| 142 | /* |
| 143 | ** Allocate a new SmtpSession object. |
| 144 | ** |
| 145 | ** Both zFrom and zDest must be specified for a client side SMTP connection. |
| 146 | ** For a server-side, specify only zFrom. |
| 147 | */ |
| 148 | SmtpSession *smtp_session_new( |
| 149 | const char *zFrom, /* Domain name of our end. */ |
| 150 | const char *zDest, /* Domain of the other end. */ |
| 151 | u32 smtpFlags, /* Flags */ |
| 152 | ... /* Arguments depending on the flags */ |
| 153 | ){ |
| 154 | SmtpSession *p; |
| 155 | va_list ap; |
| 156 | UrlData url; |
| 157 | |
| 158 | p = fossil_malloc( sizeof(*p) ); |
| 159 | memset(p, 0, sizeof(*p)); |
| 160 | p->zFrom = zFrom; |
| 161 | p->zDest = zDest; |
| 162 | p->zLabel = zDest==0 ? "CS" : "SC"; |
| 163 | p->smtpFlags = smtpFlags; |
| 164 | va_start(ap, smtpFlags); |
| 165 | if( smtpFlags & SMTP_TRACE_FILE ){ |
| 166 | p->logFile = va_arg(ap, FILE*); |
| 167 | }else if( smtpFlags & SMTP_TRACE_BLOB ){ |
| 168 | p->pTranscript = va_arg(ap, Blob*); |
| 169 | } |
| 170 | va_end(ap); |
| 171 | p->zHostname = smtp_mx_host(zDest); |
| 172 | if( p->zHostname==0 ){ |
| 173 | p->zErr = mprintf("cannot locate SMTP server for \"%s\"", zDest); |
| 174 | return p; |
| 175 | } |
| 176 | memset(&url, 0, sizeof(url)); |
| 177 | url.name = p->zHostname; |
| 178 | url.port = 25; |
| 179 | socket_global_init(); |
| 180 | if( socket_open(&url) ){ |
| 181 | p->zErr = socket_errmsg(); |
| 182 | socket_close(); |
| 183 | } |
| 184 | return p; |
| 185 | } |
| 186 | |
| 187 | /* |
| 188 | ** Send a single line of output the SMTP client to the server. |
| 189 | */ |
| 190 | static void smtp_send_line(SmtpSession *p, const char *zFormat, ...){ |
| 191 | Blob b = empty_blob; |
| 192 | va_list ap; |
| 193 | char *z; |
| 194 | int n; |
| 195 | va_start(ap, zFormat); |
| 196 | blob_vappendf(&b, zFormat, ap); |
| 197 | va_end(ap); |
| 198 | z = blob_buffer(&b); |
| 199 | n = blob_size(&b); |
| 200 | assert( n>=2 ); |
| 201 | assert( z[n-1]=='\n' ); |
| 202 | assert( z[n-2]=='\r' ); |
| 203 | if( p->smtpFlags & SMTP_TRACE_STDOUT ){ |
| 204 | fossil_print("%c: %.*s\n", p->zLabel[1], n-2, z); |
| 205 | } |
| 206 | if( p->smtpFlags & SMTP_TRACE_FILE ){ |
| 207 | fprintf(p->logFile, "%c: %.*s\n", p->zLabel[1], n-2, z); |
| 208 | } |
| 209 | if( p->smtpFlags & SMTP_TRACE_BLOB ){ |
| 210 | blob_appendf(p->pTranscript, "%c: %.*s\n", p->zLabel[1], n-2, z); |
| 211 | } |
| 212 | socket_send(0, z, n); |
| 213 | blob_zero(&b); |
| 214 | } |
| 215 | |
| 216 | /* |
| 217 | ** Read a line of input received from the SMTP server. Append |
| 218 | ** the received line onto the end of the blob. |
| 219 | */ |
| 220 | static void smtp_recv_line(SmtpSession *p, Blob *in){ |
| 221 | int n = blob_size(in); |
| 222 | int iStart = n; |
| 223 | char *z; |
| 224 | do{ |
| 225 | size_t got; |
| 226 | blob_resize(in, n+1000); |
| 227 | z = blob_buffer(in); |
| 228 | got = socket_receive(0, z+n, 1000); |
| 229 | in->nUsed += got; |
| 230 | n += got; |
| 231 | }while( n<1 || z[n-1]!='\n' ); |
| 232 | z = blob_buffer(in) + iStart; |
| 233 | n = blob_size(in) - iStart - 1; |
| 234 | if( n && z[n-1]=='\r' ) n--; |
| 235 | if( p->smtpFlags & SMTP_TRACE_STDOUT ){ |
| 236 | fossil_print("%c: %.*s\n", p->zLabel[0], n, z); |
| 237 | } |
| 238 | if( p->smtpFlags & SMTP_TRACE_FILE ){ |
| 239 | fprintf(p->logFile, "%c: %.*s\n", p->zLabel[0], n, z); |
| 240 | } |
| 241 | if( p->smtpFlags & SMTP_TRACE_BLOB ){ |
| 242 | blob_appendf(p->pTranscript, "%c: %.*s\n", p->zLabel[0], n-2, z); |
| 243 | } |
| 244 | } |
| 245 | |
| 246 | /* |
| 247 | ** Capture a single-line server reply. |
| 248 | */ |
| 249 | static void smtp_get_reply_from_server( |
| 250 | SmtpSession *p, /* The SMTP connection */ |
| 251 | Blob *in, /* Buffer used to hold the reply */ |
| 252 | int *piCode, /* The return code */ |
| 253 | int *pbMore, /* True if the reply is not complete */ |
| 254 | char **pzArg /* Argument */ |
| 255 | ){ |
| 256 | blob_truncate(in, 0); |
| 257 | smtp_recv_line(p, in); |
| 258 | *piCode = atoi(blob_str(in)); |
| 259 | *pbMore = blob_size(in)>=4 && blob_str(in)[3]=='-'; |
| 260 | *pzArg = blob_size(in)>=4 ? blob_str(in)+4 : ""; |
| 261 | } |
| 262 | |
| 263 | /* |
| 264 | ** Have the client send a QUIT message. |
| 265 | */ |
| 266 | int smtp_client_quit(SmtpSession *p){ |
| 267 | Blob in = BLOB_INITIALIZER; |
| 268 | int iCode = 0; |
| 269 | int bMore = 0; |
| 270 | char *zArg = 0; |
| 271 | smtp_send_line(p, "QUIT\r\n"); |
| 272 | do{ |
| 273 | smtp_get_reply_from_server(p, &in, &iCode, &bMore, &zArg); |
| 274 | }while( bMore ); |
| 275 | socket_close(); |
| 276 | return 0; |
| 277 | } |
| 278 | |
| 279 | /* |
| 280 | ** Begin a client SMTP session. Wait for the initial 220 then send |
| 281 | ** the EHLO and wait for a 250. |
| 282 | ** |
| 283 | ** Return 0 on success and non-zero for a failure. |
| 284 | */ |
| 285 | int smtp_client_startup(SmtpSession *p){ |
| 286 | Blob in = BLOB_INITIALIZER; |
| 287 | int iCode = 0; |
| 288 | int bMore = 0; |
| 289 | char *zArg = 0; |
| 290 | do{ |
| 291 | smtp_get_reply_from_server(p, &in, &iCode, &bMore, &zArg); |
| 292 | }while( bMore ); |
| 293 | if( iCode!=220 ){ |
| 294 | smtp_client_quit(p); |
| 295 | return 1; |
| 296 | } |
| 297 | smtp_send_line(p, "EHLO %s\r\n", p->zFrom); |
| 298 | do{ |
| 299 | smtp_get_reply_from_server(p, &in, &iCode, &bMore, &zArg); |
| 300 | }while( bMore ); |
| 301 | if( iCode!=250 ){ |
| 302 | smtp_client_quit(p); |
| 303 | return 1; |
| 304 | } |
| 305 | return 0; |
| 306 | } |
| 307 | |
| 308 | /* |
| 309 | ** COMMAND: test-smtp-probe |
| 310 | ** |
| 311 | ** Usage: %fossil test-smtp-probe DOMAIN ME |
| 312 | ** |
| 313 | ** Interact with the SMTP server for DOMAIN by setting up a connection |
| 314 | ** and then immediately shutting it back down. Log all interaction |
| 315 | ** on the console. Use ME as the domain name of the sender. |
| 316 | */ |
| 317 | void test_smtp_probe(void){ |
| 318 | char *zHost; |
| 319 | SmtpSession *p; |
| 320 | int rc; |
| 321 | if( g.argc!=4 ) usage("DOMAIN ME"); |
| 322 | zHost = smtp_mx_host(g.argv[2]); |
| 323 | if( zHost==0 ){ |
| 324 | fossil_fatal("cannot resolve the MX for \"%s\"", g.argv[2]); |
| 325 | } |
| 326 | fossil_print("Contacting host \"%s\"\n", zHost); |
| 327 | p = smtp_session_new(g.argv[3], zHost, SMTP_TRACE_STDOUT); |
| 328 | rc = smtp_client_startup(p); |
| 329 | if( !rc ) smtp_client_quit(p); |
| 330 | smtp_session_free(p); |
| 331 | } |
| 332 |