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 libraries 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 = (DtMailBoolean)va_arg(args, int);
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.
137 RFCTransport::~RFCTransport(void)
139 _object_valid->setFalse();
144 RFCTransport::submit(DtMailEnv & error, DtMail::Message * msg, DtMailBoolean log_msg)
146 waitentry_t * new_we;
149 // Create a list of information about all child processes.
150 if ((new_we = (waitentry_t *) malloc(sizeof(waitentry_t))) == NULL)
152 error.setError (DTME_NoMemory);
156 // fork a new process
157 switch(child_pid = (int) fork()) {
160 // if the fork fails, cleanup
162 error.setError (DTME_NoMemory);
167 // reset all signal handlers
168 for (int sig = 1; sig < NSIG; sig++)
170 (void) signal(sig, SIG_DFL);
176 format(tmp_error, msg, log_msg);
177 _exit((int)((DTMailError_t)tmp_error));
179 default: /* parent */
181 // Save information about each child process (sendmail)
182 // that we fork/exec.
183 new_we->pid = child_pid;
184 new_we->proc = this->_error_proc;
185 new_we->data = this->_smd;
186 new_we->next = _waitlist;
196 RFCTransport::format(DtMailEnv & error, DtMail::Message * dtmsg, DtMailBoolean log_msg)
198 // Clean up the message addressing for delivery.
200 // DtMailEnv * thr_error = new DtMailEnv();
201 // thr_error->clear();
203 DtMailValueSeq value;
208 DtMail::Envelope * env = dtmsg->getEnvelope(error);
210 DtMailAddressSeq addr_tokens(32);
215 env->getHeader(tmp_error, DtMailMessageTo, DTM_TRUE, value);
216 if (tmp_error.isNotSet()) {
217 to = concatValue(value);
218 DtMailAddressSeq to_tokens(16);
219 arpaPhrase(to, to_tokens);
220 rfcAliasExpand(error, *_session->mailRc(error), to_tokens);
221 appendAddrs(addr_tokens, to_tokens);
222 skinFiles(to_tokens);
223 char * new_to = addrToString(to_tokens);
224 env->setHeader(tmp_error, "To", DTM_TRUE, new_to);
228 // Clear the error structure before passing it to a function.
232 env->getHeader(tmp_error, DtMailMessageCc, DTM_TRUE, value);
233 if (tmp_error.isNotSet()) {
234 cc = concatValue(value);
235 DtMailAddressSeq cc_tokens(16);
236 arpaPhrase(cc, cc_tokens);
237 rfcAliasExpand(error, *_session->mailRc(error), cc_tokens);
238 appendAddrs(addr_tokens, cc_tokens);
239 skinFiles(cc_tokens);
240 char * new_cc = addrToString(cc_tokens);
241 env->setHeader(tmp_error, "Cc", DTM_TRUE, new_cc);
245 // Clear the error structure before passing it to a function.
249 env->getHeader(tmp_error, DtMailMessageBcc, DTM_TRUE, value);
250 if (tmp_error.isNotSet()) {
251 bcc = concatValue(value);
252 DtMailAddressSeq bcc_tokens(16);
253 arpaPhrase(bcc, bcc_tokens);
254 rfcAliasExpand(error, *_session->mailRc(error), bcc_tokens);
255 appendAddrs(addr_tokens, bcc_tokens);
260 // Note for now we ignore all errors from "rfcAliasExpand"
264 // Now we format the message.
265 // These messages do NOT include content-length as they are intended
266 // only for the delivery agent. If we are writing to local files,
267 // after remote delivery the local delivery will generate its own
268 // messages that have content-length included
273 if (strcmp(_impl, "Internet MIME") == 0) {
274 fmt = new RFCMIME(_session);
275 logFmt = new RFCMIME(_session);
278 fmt = new SunV3(_session);
279 logFmt = new SunV3(_session);
282 // Prepare to fire up the delivery agent
283 // The delivery agent preprocessor examines each addressee and if it is
284 // really a local file (eg folders) the local file is opened and its file
285 // descriptor is appended to the "log_files" array, which is allocated
286 // by the delivery agent preprocessor via 'new'. Upon return to us, if
287 // the log_count is > 0 we must format the message to be stored in a
288 // local file (include content length) and cause the message to be
289 // written to each open file
294 { // Create local scope to contain headers/bodies so that they go away
295 // as soon as they are no longer needed, before we potentially
296 // create a duplicate set for writing to local files
298 BufferMemory headers(1024);
299 BufferMemory bodies(8192);
302 //call unsetIsWriteBcc so that the Bcc field will not write to headers
303 // buffer (see aix defect 177089
304 fmt->unsetIsWriteBcc();
305 fmt->msgToBuffer(error, *dtmsg, DTM_FALSE, DTM_FALSE, DTM_FALSE,
309 deliver(error, addr_tokens, headers, bodies, log_msg, &log_files, log_count);
314 // If any log files have been opened, format this message for local
315 // storage and cause the message to be written to all open files
317 tmp_error.clear(); // Used to cache error from logging to files
320 BufferMemory logHeaders(1024);
321 BufferMemory logBodies(8192);
323 assert(log_files != NULL); // if log files open, must have array
326 // Mark the message as having been read.
328 env->setHeader(error, "Status", DTM_TRUE, "RO");
330 //call setIsWriteBcc so that the Bcc field will write to logHeaders
331 // buffer (see aix defect 177089)
332 logFmt->setIsWriteBcc();
333 logFmt->msgToBuffer(tmp_error, *dtmsg, DTM_TRUE, DTM_FALSE, DTM_FALSE,
334 logHeaders, logBodies);
336 if (!tmp_error.isSet()) {
337 unsigned long iterateErrno, iterateErrno1;
339 iterateErrno = logHeaders.iterate(writeToFileDesc, log_files, log_count, DTM_TRUE);
340 iterateErrno1 = logBodies.iterate(writeToFileDesc, log_files, log_count, DTM_TRUE);
341 if ( (iterateErrno != 0) || (iterateErrno1 != 0) )
342 tmp_error.setError(DTME_ObjectCreationFailed);
346 closeLogFiles(log_files, log_count);
352 /* Comment out this code because it's part of old thread code. Why
353 execute code that does nothing if we don't have to?
354 // Tell the requestor we're all done now.
356 DtMailEventPacket packet;
358 packet.target = DTM_TARGET_TRANSPORT;
359 packet.target_object = this;
360 packet.operation = (void *)ThreadSelf();
361 packet.argument = thr_error;
362 packet.event_time = time(NULL);
364 if (_object_valid->state()) {
365 _session->writeEventData(error, &packet, sizeof(DtMailEventPacket));
369 // If no error occurred during the deliver invocation, but
370 // an error occurred during local file delivery, propagate
371 // that error into the error returned to the caller
373 if (!error.isSet() && tmp_error.isSet())
374 error.setError((DTMailError_t)tmp_error);
380 RFCTransport::deliver(DtMailEnv & error,
381 DtMailAddressSeq & addr_tokens,
384 DtMailBoolean log_msg,
393 assert(log_files != NULL); // must provide -> log_files ->
395 // We want to make an argv list that is big enough to hold all
396 // of the addresses. Of course, this may need to be expanded
397 // because of local aliases, but we'll work on that.
399 char ** argv = (char **)malloc(sizeof(char *) * (addr_tokens.length() + 5));
405 if (log_msg == DTM_TRUE) {
409 _session->mailRc(merror)->getValue(merror, "record", &log);
410 if (merror.isSet()) {
414 if (*log != '/' && *log != '~' && *log != '+' && *log != '$') {
416 _session->mailRc(merror)->getValue(merror, "outfolder", &value);
417 buf = (char *)malloc(strlen(log) + 3);
419 if (merror.isSet()) {
420 // "outfolder" is not set. Relative to home directory
424 // "outfolder" is set. Relative to folder directory
431 int fd = openLogFile(log);
434 * log_files = new int[addr_tokens.length() + 4];
435 (*log_files)[log_count++] = fd;
443 // We add the correct parameter to sendmail so that it will ignore
444 // lines with a single dot(.) in them. We also check to see
445 // if we should add a couple of optional parameters: metoo and
447 argv[argc++] = "-oi";
448 _session->mailRc(merror)->getValue(merror, "metoo", &value);
449 if (merror.isNotSet()) {
456 _session->mailRc(merror)->getValue(merror, "verbose", &value);
457 if (merror.isNotSet()) {
464 // We now look at each address. If the name starts with a + or
465 // "/" then look further. If the name contains an "@" we assume
466 // it is probably an email address. Otherwise we assume it is
467 // a file and copy it to the file system.
471 for (int addr = 0; addr < addr_tokens.length(); addr++) {
472 switch (*(addr_tokens[addr]->dtm_address)) {
476 for (at = addr_tokens[addr]->dtm_address; *at; at++) {
483 argv[argc++] = addr_tokens[addr]->dtm_address;
486 int fd = openLogFile(addr_tokens[addr]->dtm_address);
489 * log_files = new int[addr_tokens.length() + 4];
490 (*log_files)[log_count++] = fd;
496 argv[argc++] = addr_tokens[addr]->dtm_address;
502 launchSendmail(error, headers, bodies, argv);
504 assert((!log_count && ! *log_files) || (log_count && *log_files));
510 skin_comma(char * buf)
512 char * last_c = &buf[strlen(buf) - 1];
514 while(last_c > buf && isspace((unsigned char)*last_c)) {
519 if (last_c > buf && *last_c == ',') {
525 RFCTransport::arpaPhrase(const char * name, DtMailAddressSeq & tokens)
528 register const char *cp;
532 int gotlt, lastsp, didq, rem;
536 DtMailValueAddress * addr;
538 if (name == (char *) 0) {
541 /* count comma's; we may need up to one extra space per comma... */
545 cp = strchr(cp, ',');
549 for(cp += 1; *cp && isspace((unsigned char)*cp); cp++) {
554 nbufp = (char *)malloc(strlen(name) + extra);
556 char * tok_start = nbufp;
558 int count_at_comma = 0;
564 for (cp = name, cp2 = bufend; (c = *cp++) != 0;) {
568 Start of a comment, ignore it.
571 while ((c = *cp) != 0) {
575 if (*cp == 0) goto outcm;
585 if (nesting <= 0) break;
593 Start a quoted string.
594 Copy it in its entirety.
597 while ((c = *cp) != 0) {
601 if ((c = *cp) == 0) goto outqs;
607 if (gotlt == 0 || gotlt == '<') {
628 if (token && (!comma || c == '\n')) {
630 addr = new DtMailValueAddress;
631 tok_len = cp2 - tok_start;
632 addr->dtm_address = (char *)malloc(tok_len + 1);
633 memcpy(addr->dtm_address, tok_start, tok_len);
634 addr->dtm_address[tok_len] = 0;
635 addr->dtm_person = NULL;
636 addr->dtm_namespace = strdup(DtMailAddressDefault);
637 skin_comma(addr->dtm_address);
640 while(*cp && isspace((unsigned char)*cp)) {
652 count_at_comma = tokens.length();
663 for (rem = (tokens.length() - 1); tokens.length() > count_at_comma;
664 rem = (tokens.length() - 1)) {
665 DtMailValueAddress * bad_addr = tokens[rem];
680 /* FALLTHROUGH . . . */
683 if (gotlt == 0 || gotlt == '<') {
695 if (cp2 > tok_start) {
696 addr = new DtMailValueAddress;
697 addr->dtm_address = strdup(tok_start);
698 addr->dtm_person = NULL;
699 addr->dtm_namespace = strdup(DtMailAddressDefault);
700 skin_comma(addr->dtm_address);
709 // SendMsgDialog has some info that is needed here.
712 RFCTransport::initTransportData(int fds[2], SubProcessFinishedProc proc,
715 _transfds[0] = fds[0];
716 _transfds[1] = fds[1];
722 // Pass a ptr to sendmailReturnProc to SendMsgDialog so that it can
723 // call it in XtAppAddInput
726 RFCTransport::getSendmailReturnProc(void)
728 return ((void *)(&RFCTransport::sendmailReturnProc));
733 RFCTransport::launchSendmail(DtMailEnv & error,
738 // We need to retrieve the name of the sendmail program.
739 // if none is set then we use the default mailer.
742 _session->mailRc(error)->getValue(error, "sendmail", &mailer);
744 #if defined(__OpenBSD__)
745 mailer = "/usr/sbin/sendmail";
747 mailer = "/usr/lib/sendmail";
753 argv[0] = (char *)mailer;
755 // If we have only one arg, then everything goes to the log files.
756 // Don't do the fork and exec.
761 // We need a pipe to write the message to sendmail.
764 const int pipeReader = 0; // pipe[0] is read side of pipe
765 const int pipeWriter = 1; // pipe[1] is write side of pipe
767 if (pipe(inputPipe)==-1) { // Attempt to get a pipe
768 error.setError(DTME_NoMemory); // this must be really bad...
772 // We need to fork and send the data to sendmail.
773 // Use vfork when available because the only purpose
774 // of the child is to do an exec
776 pid_t childPid = DTMAIL_FORK();
777 if (childPid == 0) { // The child **********
780 // Need to clean up a bit before exec()ing the child
781 // Close all non-essential open files, signals, etc.
782 // NOTE: probably reduce priv's to invoking user too???
784 long maxOpenFiles = sysconf(_SC_OPEN_MAX);
786 if (maxOpenFiles < 32) // less than 32 descriptors?
787 maxOpenFiles = 1024; // dont believe it--assume lots
789 for (int sig = 1; sig < NSIG; sig++)
790 (void) signal(sig, SIG_DFL); // REset all signal handlers
792 // input pipe reader is stdin
793 if (SafeDup2(inputPipe[pipeReader], STDIN_FILENO) == -1)
794 _exit (1); // ERROR: exit with bad status
796 // NOTE: we leave standard output and standard error output open
797 (void) SafeClose(inputPipe[pipeWriter]); // input pipe writer n/a
798 for (int cfd = 3; cfd < maxOpenFiles; cfd++)
799 (void) SafeClose(cfd); // close all open file descriptors
802 printf("Command: %s\n",mailer);
804 while (NULL != argv[k])
806 printf("Command line %d: %s\n", k, argv[k]);
810 (void) execvp(mailer, (char * const *)argv);
812 _exit(1); // Should never get here!
818 if (childPid < 0) { // did the fork fail??
819 error.setError(DTME_NoMemory); // yes: bail
823 (void) SafeClose(inputPipe[pipeReader]); // input pipe reader n/a
827 headers.iterate(writeToFileDesc, &inputPipe[pipeWriter], 1, DTM_FALSE);
828 bodies.iterate(writeToFileDesc, &inputPipe[pipeWriter], 1, DTM_FALSE);
829 (void) SafeClose(inputPipe[pipeWriter]); // force EOF on mail age nt's input
831 // Now we wait on the condition variable until the child's
832 // process status is reported.
836 int err_ret = SafeWaitpid(childPid, &status, 0);
839 // Somebody beat us to the status of the child.
840 // Just assume the best possible outcome.
844 // If the low byte of the status code returned from wait
845 // is 0, then the high byte is the status returned from
846 // the child. If the low byte is anything else, there
848 else if (lowByte(status) == 0)
850 ret_status = highByte(status);
851 switch (ret_status) {
854 error.setError(DTME_BadMailAddress);
862 error.setError(DTME_TransportFailed);
873 RFCTransport::sendmailReturnProc(void)
876 waitentry_t * ptr, ** prev;
880 // Now that the child process (sendmail) has finished, read
881 // its pid and status from the transfds pipe.
882 if(read(_transfds[0], &new_pd,
883 sizeof(new_pd))!=sizeof(new_pd)) {
884 // ERROR - can't read pipe so just return?
885 error.setError (DTME_NoMemory);
886 error.logError(DTM_TRUE,
887 "RFCTransport: sendmailReturnProc(): Failed to read pipe\n");
894 // Loop through the waitlist which is a list of all the
895 // child processes (sendmail) that the parent exec'd. When
896 // the pid in the list matches the child process that has
897 // exited, we've found it.
899 if(ptr->pid == new_pd.pid)
905 // We couldn't match the pid so just do nothing.
913 // If the low byte of the status code returned from wait
914 // is 0, then the high byte is the status returned from
915 // the child. If the low byte is anything else, there
917 if (lowByte(new_pd.status) == 0)
919 status = highByte(new_pd.status);
926 // Now that we've identified the child process, call the proc
927 // associated with it, pass the child's pid and status and any
929 ptr->proc(new_pd.pid, status, ptr->data);
936 // When a child process finishes, child_handler writes its pid
937 // and status onto the transfds pipe. XtAppAddInput calls SendmailReturnProc
938 // to read from this pipe.
940 // The reason we don't just call SendmailReturnProc directly is twofold.
941 // The amount of processing should be kept to a minimum in a
942 // signal handler and we don't really know where X is in it's
943 // processing. It may not be appropriate to pop a dialog up.
945 RFCTransport::childHandler(void)
949 // Now that the child is finished, its a zombie process
950 // until we do the wait. wait for the child and get its
951 // pid and return status. write these to the transfds pipe.
952 // Be sure to reap all processes so that none get lost.
953 while (d.pid = (int) waitpid ((pid_t) -1, &d.status, WNOHANG))
956 SafeWrite(_transfds[1], &d, sizeof(d));
966 // Listen for the child processes when they exit. On exit from a
967 // child process, call child_handler and have it write to
968 // XtAppAddInput which will call SendmailReturnProc.
970 RFCTransport::signalRegister(void)
972 static int initialized = 0;
973 struct sigaction act;
975 if (initialized) return;
978 #if defined(hpux) || defined(_aix) || defined(linux) || \
979 (defined(sun) && OSMAJORVERSION>=5 && OSMINORVERSION>4) || defined(CSRG_BASED)
980 // SunOS 5.5 and above defined prototype for signal handler
981 act.sa_handler = (void (*)(int))&RFCTransport::childHandler;
983 // SunOS 5.4 and before defined prototype signal handler
984 act.sa_handler = (void (*)())&RFCTransport::childHandler;
986 sigemptyset(&act.sa_mask);
987 sigaddset(&act.sa_mask, SIGCHLD);
990 sigaction(SIGCHLD, &act, NULL);
996 // fork/exec the child process and return the child process pid
999 RFCTransport::startSubprocess(DtMailEnv &error, char * cmd,
1000 Buffer & headers, Buffer & bodies, char ** argv)
1007 // Create a pipe to write any necessary information
1008 // from the parent process to the child process.
1009 if(pipe(sendfds) < 0)
1011 error.setError (DTME_NoMemory);
1015 // fork a new process
1016 // Use vfork when available because the only purpose
1017 // of the child is to do an exec
1018 switch(child_pid = (int) DTMAIL_FORK()) {
1022 // if the fork fails, cleanup
1023 SafeClose(sendfds[0]);
1024 SafeClose(sendfds[1]);
1025 error.setError (DTME_NoMemory);
1030 // Need to clean up a bit before execing the child
1031 // Close all non-essential open files, signals, etc.
1032 // NOTE: probably reduce priv's to invoking user too???
1033 long maxOpenFiles = sysconf(_SC_OPEN_MAX);
1035 // less than 32 descriptors?
1036 if (maxOpenFiles < 32)
1038 // dont believe it--assume lots
1039 maxOpenFiles = 1024;
1042 // reset all signal handlers
1043 for (int sig = 1; sig < NSIG; sig++)
1045 (void) signal(sig, SIG_DFL);
1048 // The child process (sendmail) needs to read info
1049 // across the pipe from the parent process (dtmail).
1050 // input pipe reader is stdin
1051 // SafeDup2 will close stdin and dup sendfds[0] to stdin
1052 // then close sendfds[0]
1053 if (SafeDup2(sendfds[0], STDIN_FILENO) == -1)
1055 // ERROR: exit with bad status
1059 // We need to close the write end of the pipe.
1060 // NOTE: we leave standard output and standard error output
1061 // open, input pipe writer n/a
1062 (void) SafeClose(sendfds[1]);
1064 // close all open file descriptors
1065 for (int cfd = 3; cfd < maxOpenFiles; cfd++)
1067 (void) SafeClose(cfd);
1071 (void) SafeExecvp(cmd, (char *const *)argv);
1073 // Should never get here!
1077 default: /* parent */
1079 // Close the input pipe reader
1080 (void) SafeClose(sendfds[0]);
1082 // Write the mail message to the pipe. The child process
1083 // (sendmail) will read from the pipe and send the message.
1084 unsigned long iterateErrno;
1086 iterateErrno = headers.iterate(writeToFileDesc, &sendfds[1],
1088 if (iterateErrno == 0)
1090 iterateErrno = bodies.iterate(writeToFileDesc, &sendfds[1],
1094 if (iterateErrno != 0)
1095 error.setError(DTME_ObjectCreationFailed);
1097 // When we are done sending the message,
1098 // force EOF on mail agent's input
1099 (void) SafeClose(sendfds[1]);
1101 // Don't wait for the child process (sendmail) to return.
1102 // Instead, we've registered for notification (SIGCHLD)
1103 // when the child exits and will invoke a handler to
1104 // do the right thing.
1114 RFCTransport::concatValue(DtMailValueSeq & value)
1116 // Count the string sizes.
1119 int valueLength = value.length();
1120 for (int n = 0; n < valueLength; n++) {
1121 tot_size += strlen(*(value[n]));
1122 tot_size += 5; // Fudge for null, commas, and space.
1125 char * str = new char[tot_size];
1128 for (int cp = 0; cp < valueLength; cp++) {
1129 strcat(str, *(value[cp]));
1130 if (cp != (valueLength - 1)) {
1139 RFCTransport::appendAddrs(DtMailAddressSeq & to, DtMailAddressSeq & from)
1141 int fromLength = from.length();
1143 for (int f = 0; f < fromLength; f++) {
1144 to.append(new DtMailValueAddress(*from[f]));
1149 RFCTransport::skinFiles(DtMailAddressSeq & addrs)
1151 for (int a = 0; a < addrs.length(); a++) {
1152 DtMailValueAddress * t_addr = addrs[a];
1153 if (*t_addr->dtm_address == '+' ||
1154 *t_addr->dtm_address == '/') {
1156 for (const char * c = t_addr->dtm_address; *c; c++) {
1172 RFCTransport::addrToString(DtMailAddressSeq & addrs)
1174 // Compute worse case string size.
1177 int addrsLength = addrs.length();
1178 for (int s = 0; s < addrsLength; s++) {
1179 DtMailValueAddress * s_addr = addrs[s];
1180 len += strlen(s_addr->dtm_address) + 5;
1184 char * addr_str = new char[len];
1187 for (int c = 0; c < addrsLength; c++) {
1188 DtMailValueAddress * c_addr = addrs[c];
1190 strcat(addr_str, ", ");
1192 strcat(addr_str, c_addr->dtm_address);
1199 RFCTransport::openLogFile(const char * path)
1204 char * exp_path = _session->expandPath(error, path);
1208 int fd = SafeOpen(exp_path, O_RDWR | O_APPEND | O_CREAT, 0600);
1214 // Generate the Unix From line...
1217 GetPasswordEntry(pw);
1219 char *from_buf = new char[256];
1220 char *time_buf = new char[256];
1221 time_t now = time(NULL);
1222 SafeCtime(&now, time_buf, sizeof(time_buf));
1224 sprintf(from_buf, "From %s %s", pw.pw_name, time_buf);
1225 SafeWrite(fd, from_buf, strlen(from_buf));
1234 RFCTransport::closeLogFiles(int * files, int file_cnt)
1236 for (int fd = 0; fd < file_cnt; fd++) {
1237 SafeWrite(files[fd], "\n", 1);
1238 SafeClose(files[fd]);
1243 RFCWriteMessage(DtMailEnv & error,
1244 DtMail::Session * session,
1246 DtMail::Message * msg)
1249 BufferMemory headers(1024);
1250 BufferMemory bodies(8192);
1252 fmt = new RFCMIME(session);
1253 //call setIsWriteBcc so that the Bcc field will write to headers
1254 // buffer (see aix defect 177089)
1255 fmt->setIsWriteBcc();
1256 fmt->msgToBuffer(error, *msg, DTM_TRUE, DTM_TRUE, DTM_FALSE,
1259 if (error.isSet()) {
1263 int fd = SafeOpen(path, O_RDWR | O_CREAT | O_TRUNC, 0600);
1266 error.setError(DTME_ObjectCreationFailed);
1271 char *fsname=(char *)error.getClient();
1273 int len=headers.getSize()+bodies.getSize();
1275 printf("\n message body len=%d",len);
1277 if( error.isSet() || !FileSystemSpace(path, len,&fsname) )
1279 error.setError(DTME_OutOfSpace);
1280 error.setClient((void *)fsname);
1286 unsigned long iterateErrno;
1288 iterateErrno = headers.iterate(writeToFileDesc, &fd, 1, DTM_FALSE);
1289 if (iterateErrno == 0)
1290 iterateErrno = bodies.iterate(writeToFileDesc, &fd, 1, DTM_FALSE);
1292 if (iterateErrno != 0)
1293 error.setError(DTME_ObjectCreationFailed);