2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
27 * $TOG: RFCTransport.C /main/18 1998/07/24 16:09:46 mgreess $
29 * RESTRICTED CONFIDENTIAL INFORMATION:
31 * The information in this document is subject to special
32 * restrictions in a confidential disclosure agreement between
33 * HP, IBM, Sun, USL, SCO and Univel. Do not distribute this
34 * document outside HP, IBM, Sun, USL, SCO, or Univel without
35 * Sun's specific written approval. This document and all copies
36 * and derivative works thereof must be returned or destroyed at
39 * Copyright 1993, 1994, 1995 Sun Microsystems, Inc. All rights reserved.
44 #ifndef I_HAVE_NO_IDENT
48 #include <DtMail/Buffer.hh>
61 #include <DtMail/DtMail.hh>
62 #include <DtMail/DtMailP.hh>
64 #include "SigChldImpl.hh"
67 #include "AliasExpand.hh"
68 #include <DtMail/Threads.hh>
69 #include <DtMail/IO.hh>
72 #define DTMAIL_FORK vfork
74 #define DTMAIL_FORK fork
77 // pipe between childHandler and XtAppAddInput
78 static int _transfds[2];
79 // list of children that have been forked
80 static waitentry_t *_waitlist;
82 // Note on error handling in wroteToFileDesc: this is used
83 // to write e-mail to all open *files* (e.g. recording to
84 // file, mail to file), so we attempt to write to all file
87 writeToFileDesc(const char * buf, int len, va_list args)
89 int * fds = va_arg(args, int *);
90 int cnt = va_arg(args, int);
91 DtMailBoolean strip = va_arg(args, DtMailBoolean);
93 unsigned long saveErrno = 0; // Initially no error recorded
95 for (int fd = 0; fd < cnt; fd++) {
99 status = SafeWriteStrip(fds[fd], buf, len);
101 status = SafeWrite(fds[fd], buf, len);
102 } while (status < 0 && errno == EAGAIN);
104 if (status < 0 && errno != 0) // Did an error occur??
105 saveErrno = (unsigned long)errno; // Yes: remember "last" errno
108 DtMailProcessClientEvents();
109 #endif /* DEAD_WOOD */
112 return(saveErrno); // return last error recorded
115 RFCTransport::RFCTransport(DtMailEnv & error,
116 DtMail::Session * session,
117 DtMailStatusCallback cb,
120 : DtMail::Transport(error, session, cb, cb_data)
124 _object_valid = new Condition;
125 _object_valid->setTrue();
127 _impl = strdup(impl);
129 // Set up the handlers so that we are notified when a child
130 // process exits and do the right thing.
134 RFCTransport::~RFCTransport(void)
136 _object_valid->setFalse();
141 RFCTransport::submit(DtMailEnv & error, DtMail::Message * msg, DtMailBoolean log_msg)
143 waitentry_t * new_we;
146 // Create a list of information about all child processes.
147 if ((new_we = (waitentry_t *) malloc(sizeof(waitentry_t))) == NULL)
149 error.setError (DTME_NoMemory);
153 // fork a new process
154 switch(child_pid = (int) fork()) {
157 // if the fork fails, cleanup
159 error.setError (DTME_NoMemory);
164 // reset all signal handlers
165 for (int sig = 1; sig < NSIG; sig++)
167 (void) signal(sig, SIG_DFL);
173 format(tmp_error, msg, log_msg);
174 _exit((int)((DTMailError_t)tmp_error));
176 default: /* parent */
178 // Save information about each child process (sendmail)
179 // that we fork/exec.
180 new_we->pid = child_pid;
181 new_we->proc = this->_error_proc;
182 new_we->data = this->_smd;
183 new_we->next = _waitlist;
193 RFCTransport::format(DtMailEnv & error, DtMail::Message * dtmsg, DtMailBoolean log_msg)
195 // Clean up the message addressing for delivery.
197 // DtMailEnv * thr_error = new DtMailEnv();
198 // thr_error->clear();
200 DtMailValueSeq value;
205 DtMail::Envelope * env = dtmsg->getEnvelope(error);
207 DtMailAddressSeq addr_tokens(32);
212 env->getHeader(tmp_error, DtMailMessageTo, DTM_TRUE, value);
213 if (tmp_error.isNotSet()) {
214 to = concatValue(value);
215 DtMailAddressSeq to_tokens(16);
216 arpaPhrase(to, to_tokens);
217 rfcAliasExpand(error, *_session->mailRc(error), to_tokens);
218 appendAddrs(addr_tokens, to_tokens);
219 skinFiles(to_tokens);
220 char * new_to = addrToString(to_tokens);
221 env->setHeader(tmp_error, "To", DTM_TRUE, new_to);
225 // Clear the error structure before passing it to a function.
229 env->getHeader(tmp_error, DtMailMessageCc, DTM_TRUE, value);
230 if (tmp_error.isNotSet()) {
231 cc = concatValue(value);
232 DtMailAddressSeq cc_tokens(16);
233 arpaPhrase(cc, cc_tokens);
234 rfcAliasExpand(error, *_session->mailRc(error), cc_tokens);
235 appendAddrs(addr_tokens, cc_tokens);
236 skinFiles(cc_tokens);
237 char * new_cc = addrToString(cc_tokens);
238 env->setHeader(tmp_error, "Cc", DTM_TRUE, new_cc);
242 // Clear the error structure before passing it to a function.
246 env->getHeader(tmp_error, DtMailMessageBcc, DTM_TRUE, value);
247 if (tmp_error.isNotSet()) {
248 bcc = concatValue(value);
249 DtMailAddressSeq bcc_tokens(16);
250 arpaPhrase(bcc, bcc_tokens);
251 rfcAliasExpand(error, *_session->mailRc(error), bcc_tokens);
252 appendAddrs(addr_tokens, bcc_tokens);
257 // Note for now we ignore all errors from "rfcAliasExpand"
261 // Now we format the message.
262 // These messages do NOT include content-length as they are intended
263 // only for the delivery agent. If we are writing to local files,
264 // after remote delivery the local delivery will generate its own
265 // messages that have content-length included
270 if (strcmp(_impl, "Internet MIME") == 0) {
271 fmt = new RFCMIME(_session);
272 logFmt = new RFCMIME(_session);
275 fmt = new SunV3(_session);
276 logFmt = new SunV3(_session);
279 // Prepare to fire up the delivery agent
280 // The delivery agent preprocessor examines each addressee and if it is
281 // really a local file (eg folders) the local file is opened and its file
282 // descriptor is appended to the "log_files" array, which is allocated
283 // by the delivery agent preprocessor via 'new'. Upon return to us, if
284 // the log_count is > 0 we must format the message to be stored in a
285 // local file (include content length) and cause the message to be
286 // written to each open file
291 { // Create local scope to contain headers/bodies so that they go away
292 // as soon as they are no longer needed, before we potentially
293 // create a duplicate set for writing to local files
295 BufferMemory headers(1024);
296 BufferMemory bodies(8192);
299 //call unsetIsWriteBcc so that the Bcc field will not write to headers
300 // buffer (see aix defect 177089
301 fmt->unsetIsWriteBcc();
302 fmt->msgToBuffer(error, *dtmsg, DTM_FALSE, DTM_FALSE, DTM_FALSE,
306 deliver(error, addr_tokens, headers, bodies, log_msg, &log_files, log_count);
311 // If any log files have been opened, format this message for local
312 // storage and cause the message to be written to all open files
314 tmp_error.clear(); // Used to cache error from logging to files
317 BufferMemory logHeaders(1024);
318 BufferMemory logBodies(8192);
320 assert(log_files != NULL); // if log files open, must have array
323 // Mark the message as having been read.
325 env->setHeader(error, "Status", DTM_TRUE, "RO");
327 //call setIsWriteBcc so that the Bcc field will write to logHeaders
328 // buffer (see aix defect 177089)
329 logFmt->setIsWriteBcc();
330 logFmt->msgToBuffer(tmp_error, *dtmsg, DTM_TRUE, DTM_FALSE, DTM_FALSE,
331 logHeaders, logBodies);
333 if (!tmp_error.isSet()) {
334 unsigned long iterateErrno, iterateErrno1;
336 iterateErrno = logHeaders.iterate(writeToFileDesc, log_files, log_count, DTM_TRUE);
337 iterateErrno1 = logBodies.iterate(writeToFileDesc, log_files, log_count, DTM_TRUE);
338 if ( (iterateErrno != 0) || (iterateErrno1 != 0) )
339 tmp_error.setError(DTME_ObjectCreationFailed);
343 closeLogFiles(log_files, log_count);
349 /* Comment out this code because it's part of old thread code. Why
350 execute code that does nothing if we don't have to?
351 // Tell the requestor we're all done now.
353 DtMailEventPacket packet;
355 packet.target = DTM_TARGET_TRANSPORT;
356 packet.target_object = this;
357 packet.operation = (void *)ThreadSelf();
358 packet.argument = thr_error;
359 packet.event_time = time(NULL);
361 if (_object_valid->state()) {
362 _session->writeEventData(error, &packet, sizeof(DtMailEventPacket));
366 // If no error occurred during the deliver invocation, but
367 // an error occurred during local file delivery, propagate
368 // that error into the error returned to the caller
370 if (!error.isSet() && tmp_error.isSet())
371 error.setError((DTMailError_t)tmp_error);
377 RFCTransport::deliver(DtMailEnv & error,
378 DtMailAddressSeq & addr_tokens,
381 DtMailBoolean log_msg,
390 assert(log_files != NULL); // must provide -> log_files ->
392 // We want to make an argv list that is big enough to hold all
393 // of the addresses. Of course, this may need to be expanded
394 // because of local aliases, but we'll work on that.
396 char ** argv = (char **)malloc(sizeof(char *) * (addr_tokens.length() + 5));
402 if (log_msg == DTM_TRUE) {
406 _session->mailRc(merror)->getValue(merror, "record", &log);
407 if (merror.isSet()) {
411 if (*log != '/' && *log != '~' && *log != '+' && *log != '$') {
413 _session->mailRc(merror)->getValue(merror, "outfolder", &value);
414 buf = (char *)malloc(strlen(log) + 3);
416 if (merror.isSet()) {
417 // "outfolder" is not set. Relative to home directory
421 // "outfolder" is set. Relative to folder directory
428 int fd = openLogFile(log);
431 * log_files = new int[addr_tokens.length() + 4];
432 (*log_files)[log_count++] = fd;
440 // We add the correct parameter to sendmail so that it will ignore
441 // lines with a single dot(.) in them. We also check to see
442 // if we should add a couple of optional parameters: metoo and
444 argv[argc++] = "-oi";
445 _session->mailRc(merror)->getValue(merror, "metoo", &value);
446 if (merror.isNotSet()) {
453 _session->mailRc(merror)->getValue(merror, "verbose", &value);
454 if (merror.isNotSet()) {
461 // We now look at each address. If the name starts with a + or
462 // "/" then look further. If the name contains an "@" we assume
463 // it is probably an email address. Otherwise we assume it is
464 // a file and copy it to the file system.
468 for (int addr = 0; addr < addr_tokens.length(); addr++) {
469 switch (*(addr_tokens[addr]->dtm_address)) {
473 for (at = addr_tokens[addr]->dtm_address; *at; at++) {
480 argv[argc++] = addr_tokens[addr]->dtm_address;
483 int fd = openLogFile(addr_tokens[addr]->dtm_address);
486 * log_files = new int[addr_tokens.length() + 4];
487 (*log_files)[log_count++] = fd;
493 argv[argc++] = addr_tokens[addr]->dtm_address;
499 launchSendmail(error, headers, bodies, argv);
501 assert((!log_count && ! *log_files) || (log_count && *log_files));
507 skin_comma(char * buf)
509 char * last_c = &buf[strlen(buf) - 1];
511 while(last_c > buf && isspace((unsigned char)*last_c)) {
516 if (last_c > buf && *last_c == ',') {
522 RFCTransport::arpaPhrase(const char * name, DtMailAddressSeq & tokens)
525 register const char *cp;
529 int gotlt, lastsp, didq, rem;
533 DtMailValueAddress * addr;
535 if (name == (char *) 0) {
538 /* count comma's; we may need up to one extra space per comma... */
542 cp = strchr(cp, ',');
546 for(cp += 1; *cp && isspace((unsigned char)*cp); cp++) {
551 nbufp = (char *)malloc(strlen(name) + extra);
553 char * tok_start = nbufp;
555 int count_at_comma = 0;
561 for (cp = name, cp2 = bufend; (c = *cp++) != 0;) {
565 Start of a comment, ignore it.
568 while ((c = *cp) != 0) {
572 if (*cp == 0) goto outcm;
582 if (nesting <= 0) break;
590 Start a quoted string.
591 Copy it in its entirety.
594 while ((c = *cp) != 0) {
598 if ((c = *cp) == 0) goto outqs;
604 if (gotlt == 0 || gotlt == '<') {
625 if (token && (!comma || c == '\n')) {
627 addr = new DtMailValueAddress;
628 tok_len = cp2 - tok_start;
629 addr->dtm_address = (char *)malloc(tok_len + 1);
630 memcpy(addr->dtm_address, tok_start, tok_len);
631 addr->dtm_address[tok_len] = 0;
632 addr->dtm_person = NULL;
633 addr->dtm_namespace = strdup(DtMailAddressDefault);
634 skin_comma(addr->dtm_address);
637 while(*cp && isspace((unsigned char)*cp)) {
649 count_at_comma = tokens.length();
660 for (rem = (tokens.length() - 1); tokens.length() > count_at_comma;
661 rem = (tokens.length() - 1)) {
662 DtMailValueAddress * bad_addr = tokens[rem];
677 /* FALLTHROUGH . . . */
680 if (gotlt == 0 || gotlt == '<') {
692 if (cp2 > tok_start) {
693 addr = new DtMailValueAddress;
694 addr->dtm_address = strdup(tok_start);
695 addr->dtm_person = NULL;
696 addr->dtm_namespace = strdup(DtMailAddressDefault);
697 skin_comma(addr->dtm_address);
706 // SendMsgDialog has some info that is needed here.
709 RFCTransport::initTransportData(int fds[2], SubProcessFinishedProc proc,
712 _transfds[0] = fds[0];
713 _transfds[1] = fds[1];
719 // Pass a ptr to sendmailReturnProc to SendMsgDialog so that it can
720 // call it in XtAppAddInput
723 RFCTransport::getSendmailReturnProc(void)
725 return ((void *)(&RFCTransport::sendmailReturnProc));
730 RFCTransport::launchSendmail(DtMailEnv & error,
735 // We need to retrieve the name of the sendmail program.
736 // if none is set then we use the default mailer.
739 _session->mailRc(error)->getValue(error, "sendmail", &mailer);
741 #if defined(USL) || defined(__uxp__)
742 mailer = "/usr/ucblib/sendmail";
744 mailer = "/usr/lib/sendmail";
750 argv[0] = (char *)mailer;
752 // If we have only one arg, then everything goes to the log files.
753 // Don't do the fork and exec.
758 // We need a pipe to write the message to sendmail.
761 const int pipeReader = 0; // pipe[0] is read side of pipe
762 const int pipeWriter = 1; // pipe[1] is write side of pipe
764 if (pipe(inputPipe)==-1) { // Attempt to get a pipe
765 error.setError(DTME_NoMemory); // this must be really bad...
769 // We need to fork and send the data to sendmail.
770 // Use vfork when available because the only purpose
771 // of the child is to do an exec
773 pid_t childPid = DTMAIL_FORK();
774 if (childPid == 0) { // The child **********
777 // Need to clean up a bit before exec()ing the child
778 // Close all non-essential open files, signals, etc.
779 // NOTE: probably reduce priv's to invoking user too???
781 long maxOpenFiles = sysconf(_SC_OPEN_MAX);
783 if (maxOpenFiles < 32) // less than 32 descriptors?
784 maxOpenFiles = 1024; // dont believe it--assume lots
786 for (int sig = 1; sig < NSIG; sig++)
787 (void) signal(sig, SIG_DFL); // REset all signal handlers
789 // input pipe reader is stdin
790 if (SafeDup2(inputPipe[pipeReader], STDIN_FILENO) == -1)
791 _exit (1); // ERROR: exit with bad status
793 // NOTE: we leave standard output and standard error output open
794 (void) SafeClose(inputPipe[pipeWriter]); // input pipe writer n/a
795 for (int cfd = 3; cfd < maxOpenFiles; cfd++)
796 (void) SafeClose(cfd); // close all open file descriptors
799 printf("Command: %s\n",mailer);
801 while (NULL != argv[k])
803 printf("Command line %d: %s\n", k, argv[k]);
807 (void) execvp(mailer, (char * const *)argv);
809 _exit(1); // Should never get here!
815 if (childPid < 0) { // did the fork fail??
816 error.setError(DTME_NoMemory); // yes: bail
820 (void) SafeClose(inputPipe[pipeReader]); // input pipe reader n/a
824 headers.iterate(writeToFileDesc, &inputPipe[pipeWriter], 1, DTM_FALSE);
825 bodies.iterate(writeToFileDesc, &inputPipe[pipeWriter], 1, DTM_FALSE);
826 (void) SafeClose(inputPipe[pipeWriter]); // force EOF on mail age nt's input
828 // Now we wait on the condition variable until the child's
829 // process status is reported.
833 int err_ret = SafeWaitpid(childPid, &status, 0);
836 // Somebody beat us to the status of the child.
837 // Just assume the best possible outcome.
841 // If the low byte of the status code returned from wait
842 // is 0, then the high byte is the status returned from
843 // the child. If the low byte is anything else, there
845 else if (lowByte(status) == 0)
847 ret_status = highByte(status);
848 switch (ret_status) {
851 error.setError(DTME_BadMailAddress);
859 error.setError(DTME_TransportFailed);
870 RFCTransport::sendmailReturnProc(void)
873 waitentry_t * ptr, ** prev;
877 // Now that the child process (sendmail) has finished, read
878 // its pid and status from the transfds pipe.
879 if(read(_transfds[0], &new_pd,
880 sizeof(new_pd))!=sizeof(new_pd)) {
881 // ERROR - can't read pipe so just return?
882 error.setError (DTME_NoMemory);
883 error.logError(DTM_TRUE,
884 "RFCTransport: sendmailReturnProc(): Failed to read pipe\n");
891 // Loop through the waitlist which is a list of all the
892 // child processes (sendmail) that the parent exec'd. When
893 // the pid in the list matches the child process that has
894 // exited, we've found it.
896 if(ptr->pid == new_pd.pid)
902 // We couldn't match the pid so just do nothing.
910 // If the low byte of the status code returned from wait
911 // is 0, then the high byte is the status returned from
912 // the child. If the low byte is anything else, there
914 if (lowByte(new_pd.status) == 0)
916 status = highByte(new_pd.status);
923 // Now that we've identified the child process, call the proc
924 // associated with it, pass the child's pid and status and any
926 ptr->proc(new_pd.pid, status, ptr->data);
933 // When a child process finishes, child_handler writes its pid
934 // and status onto the transfds pipe. XtAppAddInput calls SendmailReturnProc
935 // to read from this pipe.
937 // The reason we don't just call SendmailReturnProc directly is twofold.
938 // The amount of processing should be kept to a minimum in a
939 // signal handler and we don't really know where X is in it's
940 // processing. It may not be appropriate to pop a dialog up.
942 RFCTransport::childHandler(void)
946 // Now that the child is finished, its a zombie process
947 // until we do the wait. wait for the child and get its
948 // pid and return status. write these to the transfds pipe.
949 // Be sure to reap all processes so that none get lost.
950 while (d.pid = (int) waitpid ((pid_t) -1, &d.status, WNOHANG))
953 SafeWrite(_transfds[1], &d, sizeof(d));
963 // Listen for the child processes when they exit. On exit from a
964 // child process, call child_handler and have it write to
965 // XtAppAddInput which will call SendmailReturnProc.
967 RFCTransport::signalRegister(void)
969 static int initialized = 0;
970 struct sigaction act;
972 if (initialized) return;
975 #if defined(hpux) || defined(_aix) || defined(__osf__) || defined(linux) || \
976 (defined(sun) && OSMAJORVERSION>=5 && OSMINORVERSION>4)
977 // SunOS 5.5 and above defined prototype for signal handler
978 act.sa_handler = (void (*)(int))&RFCTransport::childHandler;
980 // SunOS 5.4 and before defined prototype signal handler
981 act.sa_handler = (void (*)())&RFCTransport::childHandler;
983 sigemptyset(&act.sa_mask);
984 sigaddset(&act.sa_mask, SIGCHLD);
987 sigaction(SIGCHLD, &act, NULL);
993 // fork/exec the child process and return the child process pid
996 RFCTransport::startSubprocess(DtMailEnv &error, char * cmd,
997 Buffer & headers, Buffer & bodies, char ** argv)
1004 // Create a pipe to write any necessary information
1005 // from the parent process to the child process.
1006 if(pipe(sendfds) < 0)
1008 error.setError (DTME_NoMemory);
1012 // fork a new process
1013 // Use vfork when available because the only purpose
1014 // of the child is to do an exec
1015 switch(child_pid = (int) DTMAIL_FORK()) {
1019 // if the fork fails, cleanup
1020 SafeClose(sendfds[0]);
1021 SafeClose(sendfds[1]);
1022 error.setError (DTME_NoMemory);
1027 // Need to clean up a bit before execing the child
1028 // Close all non-essential open files, signals, etc.
1029 // NOTE: probably reduce priv's to invoking user too???
1030 long maxOpenFiles = sysconf(_SC_OPEN_MAX);
1032 // less than 32 descriptors?
1033 if (maxOpenFiles < 32)
1035 // dont believe it--assume lots
1036 maxOpenFiles = 1024;
1039 // reset all signal handlers
1040 for (int sig = 1; sig < NSIG; sig++)
1042 (void) signal(sig, SIG_DFL);
1045 // The child process (sendmail) needs to read info
1046 // across the pipe from the parent process (dtmail).
1047 // input pipe reader is stdin
1048 // SafeDup2 will close stdin and dup sendfds[0] to stdin
1049 // then close sendfds[0]
1050 if (SafeDup2(sendfds[0], STDIN_FILENO) == -1)
1052 // ERROR: exit with bad status
1056 // We need to close the write end of the pipe.
1057 // NOTE: we leave standard output and standard error output
1058 // open, input pipe writer n/a
1059 (void) SafeClose(sendfds[1]);
1061 // close all open file descriptors
1062 for (int cfd = 3; cfd < maxOpenFiles; cfd++)
1064 (void) SafeClose(cfd);
1068 (void) SafeExecvp(cmd, (char *const *)argv);
1070 // Should never get here!
1074 default: /* parent */
1076 // Close the input pipe reader
1077 (void) SafeClose(sendfds[0]);
1079 // Write the mail message to the pipe. The child process
1080 // (sendmail) will read from the pipe and send the message.
1081 unsigned long iterateErrno;
1083 iterateErrno = headers.iterate(writeToFileDesc, &sendfds[1],
1085 if (iterateErrno == 0)
1087 iterateErrno = bodies.iterate(writeToFileDesc, &sendfds[1],
1091 if (iterateErrno != 0)
1092 error.setError(DTME_ObjectCreationFailed);
1094 // When we are done sending the message,
1095 // force EOF on mail agent's input
1096 (void) SafeClose(sendfds[1]);
1098 // Don't wait for the child process (sendmail) to return.
1099 // Instead, we've registered for notification (SIGCHLD)
1100 // when the child exits and will invoke a handler to
1101 // do the right thing.
1111 RFCTransport::concatValue(DtMailValueSeq & value)
1113 // Count the string sizes.
1116 int valueLength = value.length();
1117 for (int n = 0; n < valueLength; n++) {
1118 tot_size += strlen(*(value[n]));
1119 tot_size += 5; // Fudge for null, commas, and space.
1122 char * str = new char[tot_size];
1125 for (int cp = 0; cp < valueLength; cp++) {
1126 strcat(str, *(value[cp]));
1127 if (cp != (valueLength - 1)) {
1136 RFCTransport::appendAddrs(DtMailAddressSeq & to, DtMailAddressSeq & from)
1138 int fromLength = from.length();
1140 for (int f = 0; f < fromLength; f++) {
1141 to.append(new DtMailValueAddress(*from[f]));
1146 RFCTransport::skinFiles(DtMailAddressSeq & addrs)
1148 for (int a = 0; a < addrs.length(); a++) {
1149 DtMailValueAddress * t_addr = addrs[a];
1150 if (*t_addr->dtm_address == '+' ||
1151 *t_addr->dtm_address == '/') {
1153 for (const char * c = t_addr->dtm_address; *c; c++) {
1169 RFCTransport::addrToString(DtMailAddressSeq & addrs)
1171 // Compute worse case string size.
1174 int addrsLength = addrs.length();
1175 for (int s = 0; s < addrsLength; s++) {
1176 DtMailValueAddress * s_addr = addrs[s];
1177 len += strlen(s_addr->dtm_address) + 5;
1181 char * addr_str = new char[len];
1184 for (int c = 0; c < addrsLength; c++) {
1185 DtMailValueAddress * c_addr = addrs[c];
1187 strcat(addr_str, ", ");
1189 strcat(addr_str, c_addr->dtm_address);
1196 RFCTransport::openLogFile(const char * path)
1201 char * exp_path = _session->expandPath(error, path);
1205 int fd = SafeOpen(exp_path, O_RDWR | O_APPEND | O_CREAT, 0600);
1211 // Generate the Unix From line...
1214 GetPasswordEntry(pw);
1216 char *from_buf = new char[256];
1217 char *time_buf = new char[256];
1218 time_t now = time(NULL);
1219 SafeCtime(&now, time_buf, sizeof(time_buf));
1221 sprintf(from_buf, "From %s %s", pw.pw_name, time_buf);
1222 SafeWrite(fd, from_buf, strlen(from_buf));
1231 RFCTransport::closeLogFiles(int * files, int file_cnt)
1233 for (int fd = 0; fd < file_cnt; fd++) {
1234 SafeWrite(files[fd], "\n", 1);
1235 SafeClose(files[fd]);
1240 RFCWriteMessage(DtMailEnv & error,
1241 DtMail::Session * session,
1243 DtMail::Message * msg)
1246 BufferMemory headers(1024);
1247 BufferMemory bodies(8192);
1249 fmt = new RFCMIME(session);
1250 //call setIsWriteBcc so that the Bcc field will write to headers
1251 // buffer (see aix defect 177089)
1252 fmt->setIsWriteBcc();
1253 fmt->msgToBuffer(error, *msg, DTM_TRUE, DTM_TRUE, DTM_FALSE,
1256 if (error.isSet()) {
1260 int fd = SafeOpen(path, O_RDWR | O_CREAT | O_TRUNC, 0600);
1263 error.setError(DTME_ObjectCreationFailed);
1268 char *fsname=(char *)error.getClient();
1270 int len=headers.getSize()+bodies.getSize();
1272 printf("\n message body len=%d",len);
1274 if( error.isSet() || !FileSystemSpace(path, len,&fsname) )
1276 error.setError(DTME_OutOfSpace);
1277 error.setClient((void *)fsname);
1283 unsigned long iterateErrno;
1285 iterateErrno = headers.iterate(writeToFileDesc, &fd, 1, DTM_FALSE);
1286 if (iterateErrno == 0)
1287 iterateErrno = bodies.iterate(writeToFileDesc, &fd, 1, DTM_FALSE);
1289 if (iterateErrno != 0)
1290 error.setError(DTME_ObjectCreationFailed);