/[MITgcm]/MITgcm/tools/mpack-1.6/macnsmtp.c
ViewVC logotype

Annotation of /MITgcm/tools/mpack-1.6/macnsmtp.c

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.1 - (hide annotations) (download)
Tue Aug 26 20:45:25 2003 UTC (20 years, 8 months ago) by edhill
Branch: MAIN
CVS Tags: checkpoint64y, checkpoint64x, checkpoint58l_post, checkpoint64z, checkpoint51k_post, checkpoint57t_post, checkpoint64q, checkpoint64p, checkpoint64s, checkpoint64r, checkpoint64u, checkpoint64t, checkpoint64w, checkpoint64v, checkpoint64i, checkpoint64h, checkpoint64k, checkpoint64j, checkpoint64m, checkpoint64l, checkpoint64o, checkpoint64n, checkpoint64a, checkpoint57o_post, checkpoint64c, checkpoint64b, checkpoint64e, checkpoint64d, checkpoint64g, checkpoint64f, checkpoint52l_pre, checkpoint52e_pre, hrcube4, checkpoint58e_post, mitgcm_mapl_00, checkpoint52n_post, checkpoint52j_post, checkpoint53d_post, checkpoint58u_post, checkpoint58w_post, checkpoint54a_pre, checkpoint51o_pre, checkpoint57m_post, checkpoint55c_post, checkpoint54e_post, checkpoint52e_post, checkpoint57s_post, checkpoint51n_pre, checkpoint54a_post, checkpoint63p, checkpoint63q, checkpoint63r, checkpoint63s, checkpoint63l, checkpoint63m, checkpoint63n, checkpoint63o, checkpoint63h, checkpoint63i, checkpoint63j, checkpoint63k, checkpoint63d, checkpoint63e, checkpoint63f, checkpoint63g, checkpoint53c_post, checkpoint63a, checkpoint63b, checkpoint63c, checkpoint57k_post, checkpoint55d_pre, checkpoint57d_post, checkpoint51l_post, checkpoint57g_post, checkpoint51q_post, checkpoint64, checkpoint65, checkpoint60, checkpoint61, checkpoint62, checkpoint63, checkpoint57b_post, checkpoint57c_pre, checkpoint51j_post, checkpoint58r_post, checkpoint55j_post, checkpoint56b_post, checkpoint57i_post, checkpoint57y_post, hrcube_1, checkpoint57e_post, checkpoint66g, checkpoint66f, checkpoint66e, checkpoint66d, checkpoint66c, checkpoint66b, checkpoint66a, checkpoint66o, checkpoint66n, checkpoint66m, checkpoint66l, checkpoint66k, checkpoint66j, checkpoint66i, checkpoint66h, branch-netcdf, checkpoint52d_pre, checkpoint52l_post, checkpoint55h_post, checkpoint58n_post, checkpoint53b_post, checkpoint58x_post, checkpoint52k_post, checkpoint52b_pre, checkpoint57g_pre, checkpoint54b_post, checkpoint53b_pre, checkpoint55b_post, checkpoint58t_post, checkpoint58h_post, checkpoint65z, checkpoint65x, checkpoint65y, checkpoint54d_post, checkpoint65r, checkpoint65s, checkpoint65p, checkpoint65q, checkpoint65v, checkpoint65w, checkpoint65t, checkpoint65u, checkpoint65j, checkpoint65k, checkpoint65h, checkpoint65i, checkpoint65n, checkpoint65o, checkpoint65l, checkpoint65m, checkpoint65b, checkpoint65c, checkpoint65a, checkpoint65f, checkpoint65g, checkpoint65d, checkpoint65e, checkpoint56c_post, checkpoint52m_post, checkpoint57y_pre, checkpoint55, checkpoint53a_post, checkpoint57f_pre, checkpoint57a_post, checkpoint54, checkpoint58q_post, checkpoint54f_post, checkpoint57v_post, checkpoint59q, checkpoint59p, checkpoint55g_post, checkpoint59r, checkpoint51o_post, checkpoint51p_post, checkpoint58j_post, checkpoint52a_pre, checkpoint59e, checkpoint59d, checkpoint59g, checkpoint59f, checkpoint59a, checkpoint55f_post, checkpoint59c, checkpoint59b, checkpoint59m, checkpoint59l, checkpoint59o, checkpoint59n, checkpoint59i, checkpoint59h, checkpoint59k, checkpoint59j, checkpoint57r_post, checkpoint59, checkpoint58, checkpoint57a_pre, checkpoint55i_post, checkpoint57, checkpoint56, checkpoint51i_post, checkpoint53, checkpoint52, checkpoint51f_post, checkpoint52d_post, eckpoint57e_pre, checkpoint51r_post, checkpoint52a_post, checkpoint57h_done, checkpoint58f_post, checkpoint52b_post, checkpoint53g_post, checkpoint52f_post, branchpoint-genmake2, checkpoint57x_post, checkpoint57n_post, checkpoint52c_post, checkpoint58d_post, checkpoint58c_post, checkpoint57w_post, checkpoint57p_post, checkpint57u_post, checkpoint57f_post, checkpoint58a_post, checkpoint51h_pre, checkpoint51l_pre, checkpoint58i_post, checkpoint57q_post, checkpoint51g_post, checkpoint58g_post, ecco_c52_e35, hrcube5, checkpoint58o_post, checkpoint57z_post, checkpoint62c, checkpoint62b, checkpoint62a, checkpoint62g, checkpoint62f, checkpoint62e, checkpoint62d, checkpoint62k, checkpoint62j, checkpoint62i, checkpoint62h, checkpoint62o, checkpoint62n, checkpoint62m, checkpoint62l, checkpoint62s, checkpoint62r, checkpoint62q, checkpoint62p, checkpoint62w, checkpoint62v, checkpoint62u, checkpoint62t, checkpoint57c_post, checkpoint62z, checkpoint62y, checkpoint62x, checkpoint58y_post, checkpoint55e_post, checkpoint58k_post, checkpoint52i_post, checkpoint52j_pre, checkpoint58v_post, checkpoint53f_post, checkpoint55a_post, checkpoint51t_post, checkpoint53d_pre, checkpoint54c_post, checkpoint58s_post, checkpoint61f, checkpoint61g, checkpoint61d, checkpoint61e, checkpoint61b, checkpoint61c, checkpoint58p_post, checkpoint61a, checkpoint61n, checkpoint61o, checkpoint61l, checkpoint61m, checkpoint61j, checkpoint61k, checkpoint61h, checkpoint61i, checkpoint61v, checkpoint61w, checkpoint61t, checkpoint61u, checkpoint61r, checkpoint61s, checkpoint61p, checkpoint61q, checkpoint51n_post, checkpoint57j_post, checkpoint61z, checkpoint61x, checkpoint61y, checkpoint58b_post, checkpoint57h_pre, checkpoint51i_pre, checkpoint58m_post, checkpoint57l_post, checkpoint52i_pre, checkpoint51u_post, checkpoint52h_pre, checkpoint52f_pre, checkpoint57h_post, hrcube_2, hrcube_3, checkpoint56a_post, checkpoint51m_post, checkpoint51s_post, checkpoint55d_post, HEAD
Branch point for: branch-nonh, branch-genmake2, tg2-branch, checkpoint51n_branch, netcdf-sm0
File MIME type: text/plain
Initial check-in of the CMU "mpack" utility.  This allows us to (portably)
send MITgcm output as MIME-encoded email messages and will be used by the
"testreport" script.  The CMU license is basically an "AS-IS" statement.

1 edhill 1.1 /* macnsmtp.c -- simple async SMTP client
2     */
3     /* (C) Copyright 1995 by Carnegie Mellon University
4     * All Rights Reserved.
5     *
6     * Permission to use, copy, modify, distribute, and sell this software
7     * and its documentation for any purpose is hereby granted without
8     * fee, provided that the above copyright notice appear in all copies
9     * and that both that copyright notice and this permission notice
10     * appear in supporting documentation, and that the name of Carnegie
11     * Mellon University not be used in advertising or publicity
12     * pertaining to distribution of the software without specific,
13     * written prior permission. Carnegie Mellon University makes no
14     * representations about the suitability of this software for any
15     * purpose. It is provided "as is" without express or implied
16     * warranty.
17     *
18     * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
19     * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
20     * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
21     * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
22     * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
23     * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
24     * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
25     * SOFTWARE.
26     */
27     /* (C) Copyright 1994-1995 by Christopher J. Newman
28     * All Rights Reserved.
29     *
30     * Permission to use, copy, modify, distribute, and sell this software and its
31     * documentation for any purpose is hereby granted without fee, provided that
32     * the above copyright notice appear in all copies and that both that
33     * copyright notice and this permission notice appear in supporting
34     * documentation, and that the name of Christopher J. Newman not be used in
35     * advertising or publicity pertaining to distribution of the software without
36     * specific, written prior permission. Christopher J. Newman makes no
37     * representations about the suitability of this software for any purpose. It
38     * is provided "as is" without express or implied warranty.
39     *
40     * CHRISTOPHER J. NEWMAN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
41     * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT
42     * SHALL CHRISTOPHER J. NEWMAN BE LIABLE FOR ANY SPECIAL, INDIRECT OR
43     * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
44     * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
45     * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
46     * OF THIS SOFTWARE.
47     *
48     * Author: Christopher J. Newman
49     * Message: This is a nifty program.
50     */
51    
52     #include "macnapp.h"
53    
54     #define SMTP_PORT 25
55    
56     typedef struct {
57     na_win w;
58     void *context; /* user context */
59     short num, rcpt; /* recipient count (num), and sent (rcpt) */
60     na_smtpstat statf; /* callback */
61     na_tcp tcpid; /* TCP id */
62     short state; /* SMTP state (see below) */
63     short count; /* bytes used in linebuf */
64     short refnum; /* input file */
65     short crfound:1; /* found a CR in SMTP server data */
66     short crlf:1; /* found a CRLF in SMTP server data */
67     short crtrans:1; /* translate CR to CRLF in file */
68     long headsize; /* size of extra headers starting at data */
69     long fsize, fdone; /* file size & amount written */
70     long bufsize; /* usable buffer size */
71     Ptr buf; /* output buffer */
72     char linebuf[1024]; /* input line buffer */
73     char data[1]; /* header & envelope */
74     } na_smtpwin;
75    
76     #define sw ((na_smtpwin *) w)
77    
78     /* states: */
79     #define S_conn 0 /* connecting to server */
80     #define S_greet 1 /* waiting for greeting */
81     #define S_hello 2 /* waiting for local host lookup and HELO reply */
82     #define S_mailf 3 /* waiting for MAIL FROM reply */
83     #define S_rcpt 4 /* waiting for RCPT TO reply */
84     #define S_data 5 /* waiting for DATA continue reply */
85     #define S_send 6 /* transmitting data */
86     #define S_done 7 /* waiting for DATA success reply */
87     #define S_quit 8 /* waiting for QUIT reply */
88     #define S_wait 9 /* waiting for connection close */
89     #define S_close 10 /* closed */
90    
91     /* generate and submit SMTP command line (put command & data together with CRLF ending)
92     * returns NATCPwrite result code
93     */
94     static int SMTPsend(na_win *w, char *com, char *data)
95     {
96     char buf[512];
97     char *dest = buf;
98     int result = 0;
99    
100     while ((*dest = *com) != '\0') ++dest, ++com;
101     if (data) {
102     while ((*dest = *data++) != '\0') ++dest;
103     if (com[-1] == '<') *dest++ = '>';
104     }
105     *dest++ = '\r';
106     *dest++ = '\n';
107     result = NATCPwrite(sw->tcpid, buf, dest - buf, -1);
108    
109     return (result);
110     }
111    
112     /* do final callback
113     */
114     static void smtpclose(na_win *w, short code, short err, long size, char *data)
115     {
116     if (sw->state < S_wait) {
117     NATCPclose(sw->tcpid);
118     FSClose(sw->refnum);
119     sw->state = S_wait;
120     (*sw->statf)(sw->context, code, err, size, data);
121     }
122     }
123    
124     /* TCP read/write callback
125     */
126     static void readp(void *wh, na_tcp s, short status, long size, char *data)
127     {
128     na_win *w, **taskh;
129     char *dest;
130     short major, count, smtpcode;
131    
132     /* make sure our SMTP task still exists */
133     for (taskh = NAtask; taskh && taskh != wh; taskh = (*taskh)->task);
134     if (!taskh) return;
135    
136     /* handle TCP result */
137     w = NAlockWindow((na_win **) wh);
138     if (status == NATCP_connect) {
139     /* deal with new connection */
140     sw->state = S_greet;
141     } else if (status < 0) {
142     /* deal with TCP errors */
143     smtpclose(w, NASMTP_tcpfail, status, size, NULL);
144     if (status == NATCP_closed) sw->state = S_close;
145     } else if (status & NATCP_closing) {
146     /* deal with a closed connection */
147     if (sw->state < S_wait) {
148     smtpclose(w, NASMTP_conclosed, 0, 0, NULL);
149     }
150     } else if (status & NATCP_data) {
151     do {
152     /* buffer SMTP line */
153     dest = sw->linebuf + sw->count;
154     while (size && sw->count < sizeof (sw->linebuf)) {
155     --size, ++sw->count;
156     if (sw->crfound && *data == '\n') {
157     *--dest = '\0';
158     --sw->count;
159     ++data;
160     sw->crfound = 0;
161     sw->crlf = 1;
162     break;
163     }
164     sw->crfound = (*dest++ = *data++) == '\r';
165     }
166     if (!sw->crlf) {
167     if (sw->count == sizeof (sw->linebuf)) {
168     sw->linebuf[sw->count - 1] = '\0';
169     smtpclose(w, NASMTP_badprot, 0, 0, sw->linebuf);
170     }
171     break;
172     }
173     sw->crlf = 0;
174     /* parse SMTP result code */
175     dest = sw->linebuf;
176     if (sw->count < 3 || !isdigit(dest[0])
177     || !isdigit(dest[1]) || !isdigit(dest[2])) {
178     smtpclose(w, NASMTP_badprot, 0, 0, dest);
179     break;
180     }
181     sw->count = 0;
182     major = dest[0] - '0';
183     smtpcode = major * 100 + (dest[1] - '0') * 10 + (dest[2] - '0');
184     /* handle reply continuation */
185     if (dest[3] == '-') continue;
186     /* handle major errors */
187     if (major > 3) {
188     if (sw->state != S_rcpt) {
189     smtpclose(w, major == 4 ? NASMTP_temperr : NASMTP_permerr,
190     smtpcode, sw->state, dest + 3);
191     break;
192     }
193     (*sw->statf)(sw->context, NASMTP_badaddr, smtpcode, 0, sw->linebuf + 3);
194     }
195     dest = sw->data + sw->headsize;
196     /* state changes */
197     switch (sw->state) {
198     case S_greet:
199     if (sw->buf) {
200     SMTPsend(w, "HELO ", sw->buf);
201     if (sw->buf) DisposPtr(sw->buf);
202     }
203     sw->state = S_hello;
204     break;
205     case S_hello:
206     SMTPsend(w, "MAIL FROM:<", dest);
207     (*sw->statf)(sw->context, NASMTP_progress, 5, 0, 0);
208     sw->state = S_mailf;
209     break;
210     case S_mailf:
211     case S_rcpt:
212     count = ++sw->rcpt;
213     if (count < sw->num + 1) {
214     while (count--) {
215     while (*dest++);
216     }
217     SMTPsend(w, "RCPT TO:<", dest);
218     (*sw->statf)(sw->context, NASMTP_progress, 5 + 10 * sw->rcpt / sw->num, 0, 0);
219     } else {
220     sw->state = S_data;
221     SMTPsend(w, "DATA", 0);
222     (*sw->statf)(sw->context, NASMTP_progress, 20, 0, 0);
223     }
224     break;
225     case S_data:
226     if (major != 3) {
227     smtpclose(w, NASMTP_badprot, 0, 0, dest);
228     break;
229     }
230     sw->state = S_send;
231     if (sw->headsize) {
232     sw->buf = NewPtr(sw->bufsize = sw->headsize);
233     if (!sw->buf) {
234     smtpclose(w, NASMTP_nomem, 0, 0, NULL);
235     break;
236     }
237     memcpy(sw->buf, sw->data, sw->headsize);
238     }
239     case S_send:
240     /* NOTE: this case should never happen */
241     break;
242     case S_done:
243     sw->state = S_quit;
244     SMTPsend(w, "QUIT", NULL);
245     (*sw->statf)(sw->context, NASMTP_progress, 95, 0, 0);
246     break;
247     case S_quit:
248     smtpclose(w, NASMTP_completed, 0, 0, 0);
249     break;
250     }
251     } while (size);
252     }
253     NAunlockWindowh((na_win **) wh, w)
254     }
255    
256     /* TCP gethost callback
257     */
258     static void hostp(void *wh, na_tcp s, short status, long size, char *data)
259     {
260     na_win *w, **taskh;
261    
262     /* make sure our task still exists */
263     for (taskh = NAtask; taskh && taskh != wh; taskh = (*taskh)->task);
264     if (!taskh) return;
265    
266     /* store host/error */
267     w = NAlockWindow((na_win **) wh);
268     if (status == NATCP_connect) {
269     if (sw->state == S_hello) {
270     SMTPsend(w, "HELO ", data);
271     } else {
272     sw->buf = NewPtr(size + 1);
273     if (sw->buf == NULL) {
274     smtpclose(w, NASMTP_nomem, 0, 0, NULL);
275     } else {
276     memcpy(sw->buf, data, size + 1);
277     }
278     }
279     } else {
280     smtpclose(w, NASMTP_tcpfail, status, size, NULL);
281     }
282     NAunlockWindowh((na_win **) wh, w);
283     }
284    
285     /* translate CR to CRLF
286     */
287     static void crtocrlf(char *buf, long *size)
288     {
289     long crcount = 0;
290     char *src, *dst, *end = buf + *size;
291    
292     for (src = buf; src < end; ++src) {
293     if (src[0] == '\r') ++crcount;
294     }
295     src = end - 1;
296     for (dst = src + crcount; dst > src; *dst-- = *src--) {
297     if (*src == '\r') *dst-- = '\n';
298     }
299     *size += crcount;
300     }
301    
302     /* SMTP task
303     */
304     static short taskp(na_win *w)
305     {
306     OSErr oserr;
307    
308     if (sw->state == S_send || sw->state == S_done) {
309     /*XXX: could be generous with NewPtr() failure if a NATCPwritePending() */
310     if (!sw->bufsize) {
311     if ((sw->buf = NewPtr(8192)) == NULL) {
312     smtpclose(w, NASMTP_nomem, 0, 0, NULL);
313     return (NA_NOTPROCESSED);
314     }
315     sw->bufsize = sw->crtrans ? 4096 : 8192;
316     oserr = FSRead(sw->refnum, &sw->bufsize, sw->buf);
317     if (oserr != noErr && oserr != eofErr) sw->bufsize = 0;
318     if (!sw->bufsize) {
319     if (oserr == eofErr && sw->state == S_send) {
320     memcpy(sw->buf, "\r\n.\r\n", 5);
321     sw->bufsize = 5;
322     sw->state = S_done;
323     } else {
324     DisposPtr(sw->buf);
325     }
326     } else {
327     if (sw->crtrans) {
328     crtocrlf(sw->buf, &sw->bufsize);
329     }
330     (*sw->statf)(sw->context, NASMTP_progress, 20
331     + 70 * (sw->fdone += sw->bufsize) / sw->fsize, 0, 0);
332     }
333     }
334     if (sw->bufsize && NATCPwrite(sw->tcpid, sw->buf, sw->bufsize, 1) == NATCP_data) {
335     sw->bufsize = 0;
336     }
337     }
338    
339     return (sw->state == S_close ? NA_REQCLOSE : NA_NOTPROCESSED);
340     }
341    
342     /* SMTP close procedure
343     * IMPORTANT: if the user quits during mail transmission, we want to
344     * warn the user that mail will be lost.
345     */
346     static short closep(na_win *w)
347     {
348     if (sw->state < S_wait) {
349     /*XXX: put modal dialog here, allow abort of close */
350     if (sw->tcpid >= 0) NATCPclose(sw->tcpid);
351     FSClose(sw->refnum);
352     }
353    
354     return (NA_CLOSED);
355     }
356    
357     /* submit file to SMTP:
358     * creates SMTP task, initializes data, starts TCP connection
359     * copies from & dest addresses, so they don't need to persist
360     * task is not completed until statf() is called
361     */
362     void NASMTPsubmit(na_smtpstat statf, char *server, FSSpec *fspec, Handle headers,
363     Handle envelope, short flags, void *context)
364     {
365     long size;
366     na_win **wh, *w;
367     char *src, *dst;
368     OSErr oserr;
369    
370     /* create task */
371     size = sizeof (na_smtpwin);
372     if (headers) size += GetHandleSize(headers);
373     size += GetHandleSize(envelope);
374     wh = NAaddtask(taskp, size);
375     if (!wh) {
376     (*statf)(context, NASMTP_nomem, 0, 0, 0);
377     return;
378     }
379    
380     /* init task */
381     w = NAlockWindow(wh);
382     w->type = NA_SMTPTYPE;
383     w->closep = closep;
384     sw->context = context;
385     sw->statf = statf;
386     if (headers && (sw->headsize = GetHandleSize(headers))) {
387     memcpy(sw->data, (char *) *headers, sw->headsize);
388     }
389     size = GetHandleSize(envelope);
390     sw->num = -1;
391     dst = sw->data + sw->headsize;
392     for (src = (char *) *envelope; size; --size) {
393     if ((*dst++ = *src++) == '\0') ++sw->num;
394     }
395     if (flags & NASMTP_crtrans) sw->crtrans = 1;
396    
397     /* open file */
398     if ((oserr = HOpen(fspec->vRefNum, fspec->parID, fspec->name,
399     fsRdPerm, &sw->refnum)) != noErr) {
400     (*statf)(context, NASMTP_oserr, 0, oserr, 0);
401     NAcloseWindow(w, NA_CLOSED);
402     return;
403     }
404     GetEOF(sw->refnum, &sw->fsize);
405    
406     /* open MacTCP */
407     sw->tcpid = NATCPopen(readp, (void *) wh, server, SMTP_PORT, 0);
408     if (sw->tcpid != -1) NATCPgethost(hostp, (void *) wh);
409     NAunlockWindowh(wh, w);
410     }

  ViewVC Help
Powered by ViewVC 1.1.22