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(USL) || defined(__uxp__)
745 mailer = "/usr/ucblib/sendmail";
746 #elif defined(__OpenBSD__)
747 mailer = "/usr/sbin/sendmail";
749 mailer = "/usr/lib/sendmail";
755 argv[0] = (char *)mailer;
757 // If we have only one arg, then everything goes to the log files.
758 // Don't do the fork and exec.
763 // We need a pipe to write the message to sendmail.
766 const int pipeReader = 0; // pipe[0] is read side of pipe
767 const int pipeWriter = 1; // pipe[1] is write side of pipe
769 if (pipe(inputPipe)==-1) { // Attempt to get a pipe
770 error.setError(DTME_NoMemory); // this must be really bad...
774 // We need to fork and send the data to sendmail.
775 // Use vfork when available because the only purpose
776 // of the child is to do an exec
778 pid_t childPid = DTMAIL_FORK();
779 if (childPid == 0) { // The child **********
782 // Need to clean up a bit before exec()ing the child
783 // Close all non-essential open files, signals, etc.
784 // NOTE: probably reduce priv's to invoking user too???
786 long maxOpenFiles = sysconf(_SC_OPEN_MAX);
788 if (maxOpenFiles < 32) // less than 32 descriptors?
789 maxOpenFiles = 1024; // dont believe it--assume lots
791 for (int sig = 1; sig < NSIG; sig++)
792 (void) signal(sig, SIG_DFL); // REset all signal handlers
794 // input pipe reader is stdin
795 if (SafeDup2(inputPipe[pipeReader], STDIN_FILENO) == -1)
796 _exit (1); // ERROR: exit with bad status
798 // NOTE: we leave standard output and standard error output open
799 (void) SafeClose(inputPipe[pipeWriter]); // input pipe writer n/a
800 for (int cfd = 3; cfd < maxOpenFiles; cfd++)
801 (void) SafeClose(cfd); // close all open file descriptors
804 printf("Command: %s\n",mailer);
806 while (NULL != argv[k])
808 printf("Command line %d: %s\n", k, argv[k]);
812 (void) execvp(mailer, (char * const *)argv);
814 _exit(1); // Should never get here!
820 if (childPid < 0) { // did the fork fail??
821 error.setError(DTME_NoMemory); // yes: bail
825 (void) SafeClose(inputPipe[pipeReader]); // input pipe reader n/a
829 headers.iterate(writeToFileDesc, &inputPipe[pipeWriter], 1, DTM_FALSE);
830 bodies.iterate(writeToFileDesc, &inputPipe[pipeWriter], 1, DTM_FALSE);
831 (void) SafeClose(inputPipe[pipeWriter]); // force EOF on mail age nt's input
833 // Now we wait on the condition variable until the child's
834 // process status is reported.
838 int err_ret = SafeWaitpid(childPid, &status, 0);
841 // Somebody beat us to the status of the child.
842 // Just assume the best possible outcome.
846 // If the low byte of the status code returned from wait
847 // is 0, then the high byte is the status returned from
848 // the child. If the low byte is anything else, there
850 else if (lowByte(status) == 0)
852 ret_status = highByte(status);
853 switch (ret_status) {
856 error.setError(DTME_BadMailAddress);
864 error.setError(DTME_TransportFailed);
875 RFCTransport::sendmailReturnProc(void)
878 waitentry_t * ptr, ** prev;
882 // Now that the child process (sendmail) has finished, read
883 // its pid and status from the transfds pipe.
884 if(read(_transfds[0], &new_pd,
885 sizeof(new_pd))!=sizeof(new_pd)) {
886 // ERROR - can't read pipe so just return?
887 error.setError (DTME_NoMemory);
888 error.logError(DTM_TRUE,
889 "RFCTransport: sendmailReturnProc(): Failed to read pipe\n");
896 // Loop through the waitlist which is a list of all the
897 // child processes (sendmail) that the parent exec'd. When
898 // the pid in the list matches the child process that has
899 // exited, we've found it.
901 if(ptr->pid == new_pd.pid)
907 // We couldn't match the pid so just do nothing.
915 // If the low byte of the status code returned from wait
916 // is 0, then the high byte is the status returned from
917 // the child. If the low byte is anything else, there
919 if (lowByte(new_pd.status) == 0)
921 status = highByte(new_pd.status);
928 // Now that we've identified the child process, call the proc
929 // associated with it, pass the child's pid and status and any
931 ptr->proc(new_pd.pid, status, ptr->data);
938 // When a child process finishes, child_handler writes its pid
939 // and status onto the transfds pipe. XtAppAddInput calls SendmailReturnProc
940 // to read from this pipe.
942 // The reason we don't just call SendmailReturnProc directly is twofold.
943 // The amount of processing should be kept to a minimum in a
944 // signal handler and we don't really know where X is in it's
945 // processing. It may not be appropriate to pop a dialog up.
947 RFCTransport::childHandler(void)
951 // Now that the child is finished, its a zombie process
952 // until we do the wait. wait for the child and get its
953 // pid and return status. write these to the transfds pipe.
954 // Be sure to reap all processes so that none get lost.
955 while (d.pid = (int) waitpid ((pid_t) -1, &d.status, WNOHANG))
958 SafeWrite(_transfds[1], &d, sizeof(d));
968 // Listen for the child processes when they exit. On exit from a
969 // child process, call child_handler and have it write to
970 // XtAppAddInput which will call SendmailReturnProc.
972 RFCTransport::signalRegister(void)
974 static int initialized = 0;
975 struct sigaction act;
977 if (initialized) return;
980 #if defined(hpux) || defined(_aix) || defined(__osf__) || defined(linux) || \
981 (defined(sun) && OSMAJORVERSION>=5 && OSMINORVERSION>4) || defined(CSRG_BASED)
982 // SunOS 5.5 and above defined prototype for signal handler
983 act.sa_handler = (void (*)(int))&RFCTransport::childHandler;
985 // SunOS 5.4 and before defined prototype signal handler
986 act.sa_handler = (void (*)())&RFCTransport::childHandler;
988 sigemptyset(&act.sa_mask);
989 sigaddset(&act.sa_mask, SIGCHLD);
992 sigaction(SIGCHLD, &act, NULL);
998 // fork/exec the child process and return the child process pid
1001 RFCTransport::startSubprocess(DtMailEnv &error, char * cmd,
1002 Buffer & headers, Buffer & bodies, char ** argv)
1009 // Create a pipe to write any necessary information
1010 // from the parent process to the child process.
1011 if(pipe(sendfds) < 0)
1013 error.setError (DTME_NoMemory);
1017 // fork a new process
1018 // Use vfork when available because the only purpose
1019 // of the child is to do an exec
1020 switch(child_pid = (int) DTMAIL_FORK()) {
1024 // if the fork fails, cleanup
1025 SafeClose(sendfds[0]);
1026 SafeClose(sendfds[1]);
1027 error.setError (DTME_NoMemory);
1032 // Need to clean up a bit before execing the child
1033 // Close all non-essential open files, signals, etc.
1034 // NOTE: probably reduce priv's to invoking user too???
1035 long maxOpenFiles = sysconf(_SC_OPEN_MAX);
1037 // less than 32 descriptors?
1038 if (maxOpenFiles < 32)
1040 // dont believe it--assume lots
1041 maxOpenFiles = 1024;
1044 // reset all signal handlers
1045 for (int sig = 1; sig < NSIG; sig++)
1047 (void) signal(sig, SIG_DFL);
1050 // The child process (sendmail) needs to read info
1051 // across the pipe from the parent process (dtmail).
1052 // input pipe reader is stdin
1053 // SafeDup2 will close stdin and dup sendfds[0] to stdin
1054 // then close sendfds[0]
1055 if (SafeDup2(sendfds[0], STDIN_FILENO) == -1)
1057 // ERROR: exit with bad status
1061 // We need to close the write end of the pipe.
1062 // NOTE: we leave standard output and standard error output
1063 // open, input pipe writer n/a
1064 (void) SafeClose(sendfds[1]);
1066 // close all open file descriptors
1067 for (int cfd = 3; cfd < maxOpenFiles; cfd++)
1069 (void) SafeClose(cfd);
1073 (void) SafeExecvp(cmd, (char *const *)argv);
1075 // Should never get here!
1079 default: /* parent */
1081 // Close the input pipe reader
1082 (void) SafeClose(sendfds[0]);
1084 // Write the mail message to the pipe. The child process
1085 // (sendmail) will read from the pipe and send the message.
1086 unsigned long iterateErrno;
1088 iterateErrno = headers.iterate(writeToFileDesc, &sendfds[1],
1090 if (iterateErrno == 0)
1092 iterateErrno = bodies.iterate(writeToFileDesc, &sendfds[1],
1096 if (iterateErrno != 0)
1097 error.setError(DTME_ObjectCreationFailed);
1099 // When we are done sending the message,
1100 // force EOF on mail agent's input
1101 (void) SafeClose(sendfds[1]);
1103 // Don't wait for the child process (sendmail) to return.
1104 // Instead, we've registered for notification (SIGCHLD)
1105 // when the child exits and will invoke a handler to
1106 // do the right thing.
1116 RFCTransport::concatValue(DtMailValueSeq & value)
1118 // Count the string sizes.
1121 int valueLength = value.length();
1122 for (int n = 0; n < valueLength; n++) {
1123 tot_size += strlen(*(value[n]));
1124 tot_size += 5; // Fudge for null, commas, and space.
1127 char * str = new char[tot_size];
1130 for (int cp = 0; cp < valueLength; cp++) {
1131 strcat(str, *(value[cp]));
1132 if (cp != (valueLength - 1)) {
1141 RFCTransport::appendAddrs(DtMailAddressSeq & to, DtMailAddressSeq & from)
1143 int fromLength = from.length();
1145 for (int f = 0; f < fromLength; f++) {
1146 to.append(new DtMailValueAddress(*from[f]));
1151 RFCTransport::skinFiles(DtMailAddressSeq & addrs)
1153 for (int a = 0; a < addrs.length(); a++) {
1154 DtMailValueAddress * t_addr = addrs[a];
1155 if (*t_addr->dtm_address == '+' ||
1156 *t_addr->dtm_address == '/') {
1158 for (const char * c = t_addr->dtm_address; *c; c++) {
1174 RFCTransport::addrToString(DtMailAddressSeq & addrs)
1176 // Compute worse case string size.
1179 int addrsLength = addrs.length();
1180 for (int s = 0; s < addrsLength; s++) {
1181 DtMailValueAddress * s_addr = addrs[s];
1182 len += strlen(s_addr->dtm_address) + 5;
1186 char * addr_str = new char[len];
1189 for (int c = 0; c < addrsLength; c++) {
1190 DtMailValueAddress * c_addr = addrs[c];
1192 strcat(addr_str, ", ");
1194 strcat(addr_str, c_addr->dtm_address);
1201 RFCTransport::openLogFile(const char * path)
1206 char * exp_path = _session->expandPath(error, path);
1210 int fd = SafeOpen(exp_path, O_RDWR | O_APPEND | O_CREAT, 0600);
1216 // Generate the Unix From line...
1219 GetPasswordEntry(pw);
1221 char *from_buf = new char[256];
1222 char *time_buf = new char[256];
1223 time_t now = time(NULL);
1224 SafeCtime(&now, time_buf, sizeof(time_buf));
1226 sprintf(from_buf, "From %s %s", pw.pw_name, time_buf);
1227 SafeWrite(fd, from_buf, strlen(from_buf));
1236 RFCTransport::closeLogFiles(int * files, int file_cnt)
1238 for (int fd = 0; fd < file_cnt; fd++) {
1239 SafeWrite(files[fd], "\n", 1);
1240 SafeClose(files[fd]);
1245 RFCWriteMessage(DtMailEnv & error,
1246 DtMail::Session * session,
1248 DtMail::Message * msg)
1251 BufferMemory headers(1024);
1252 BufferMemory bodies(8192);
1254 fmt = new RFCMIME(session);
1255 //call setIsWriteBcc so that the Bcc field will write to headers
1256 // buffer (see aix defect 177089)
1257 fmt->setIsWriteBcc();
1258 fmt->msgToBuffer(error, *msg, DTM_TRUE, DTM_TRUE, DTM_FALSE,
1261 if (error.isSet()) {
1265 int fd = SafeOpen(path, O_RDWR | O_CREAT | O_TRUNC, 0600);
1268 error.setError(DTME_ObjectCreationFailed);
1273 char *fsname=(char *)error.getClient();
1275 int len=headers.getSize()+bodies.getSize();
1277 printf("\n message body len=%d",len);
1279 if( error.isSet() || !FileSystemSpace(path, len,&fsname) )
1281 error.setError(DTME_OutOfSpace);
1282 error.setClient((void *)fsname);
1288 unsigned long iterateErrno;
1290 iterateErrno = headers.iterate(writeToFileDesc, &fd, 1, DTM_FALSE);
1291 if (iterateErrno == 0)
1292 iterateErrno = bodies.iterate(writeToFileDesc, &fd, 1, DTM_FALSE);
1294 if (iterateErrno != 0)
1295 error.setError(DTME_ObjectCreationFailed);