1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License, Version 1.0 only
   6  * (the "License").  You may not use this file except in compliance
   7  * with the License.
   8  *
   9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  10  * or http://www.opensolaris.org/os/licensing.
  11  * See the License for the specific language governing permissions
  12  * and limitations under the License.
  13  *
  14  * When distributing Covered Code, include this CDDL HEADER in each
  15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  16  * If applicable, add the following below this CDDL HEADER, with the
  17  * fields enclosed by brackets "[]" replaced with your own identifying
  18  * information: Portions Copyright [yyyy] [name of copyright owner]
  19  *
  20  * CDDL HEADER END
  21  */
  22 /*
  23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 /*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T     */
  28 /*        All Rights Reserved   */
  29 
  30 #pragma ident   "%Z%%M% %I%     %E% SMI"
  31 
  32 #include "mail.h"
  33 
  34 /*
  35     NAME
  36         copylet - copy a given letter to a file pointer
  37 
  38     SYNOPSIS
  39         int copylet(int letnum, FILE *f, int type)
  40 
  41     DESCRIPTION
  42         Copylet() will copy the letter "letnum" to the
  43         given file pointer.
  44 
  45                 letnum  -> index into: letter table
  46                 f       -> file pointer to copy file to
  47                 type    -> copy type
  48 
  49         Returns TRUE on a completely successful copy.
  50 */
  51 
  52 int
  53 copylet(int letnum, FILE *f, int type) 
  54 {
  55         int             pos = ftell(f);
  56         int             rc  = xxxcopylet(letnum, f, type);
  57 
  58         if (fflush(f) != 0)
  59                 rc = FALSE;
  60         
  61         /*
  62          * On error, truncate the file to its original position so that a
  63          * partial message is not left in the mailbox.
  64          */
  65         if (rc == FALSE)
  66                 ftruncate(fileno(f), pos);
  67 
  68         return(rc);
  69 }
  70 
  71 int
  72 xxxcopylet(int letnum, FILE *f, int type) 
  73 {
  74         static char     pn[] = "copylet";
  75         char    buf[LSIZE], lastc;
  76         char    wbuf[LSIZE];
  77         int     n;
  78         long    i, k;
  79         int     num;
  80         int     rtrncont = 1;   /* True: nondelivery&content included, or regular mail */
  81         int     suppress = FALSE;
  82         int     sav_suppress = FALSE; /* Did we suppress previous hdr line? */
  83         int     print_from_struct = FALSE; /* print from hdrlines struct */
  84                                            /* rather than fgets() buffer */
  85         int     pushrest = FALSE;
  86         int     ctf = FALSE;
  87         int     didafflines = FALSE;    /* Did we already put out any */
  88                                         /* H_AFWDFROM lines? */
  89         int     didrcvlines = FALSE;    /* Did we already put out any */
  90                                         /* H_RECEIVED lines? */
  91         long    clen = -1L;
  92         int     htype;                  /* header type */
  93         int     sav_htype;      /* Header type of last non-H_CONT header line */
  94         struct hdrs *hptr;
  95 
  96         if (!sending) {
  97                 /* Clear out any saved header info from previous message */
  98                 clr_hinfo();
  99         }
 100 
 101         fseek(tmpf, let[letnum].adr, 0);
 102         /* Get size of message as stored into tempfile by copymt() */
 103         k = let[letnum+1].adr - let[letnum].adr;
 104         Dout(pn, 1, "(letnum = %d, type = %d), k = %ld\n", letnum, type, k);
 105         while (k>0) {        /* process header */
 106                 num = ((k < sizeof(buf)) ? k+1 : sizeof(buf));
 107                 if (fgets (buf, num, tmpf) == NULL) {
 108                         return (FALSE);
 109                 }
 110                 if ((n = strlen (buf)) == 0) {
 111                         k = 0;
 112                         break;
 113                 }
 114                 k -= n;
 115                 lastc = buf[n-1];
 116                 if (pushrest) {
 117                         pushrest = (lastc != '\n');
 118                         continue;
 119                 }
 120                 htype = isheader (buf, &ctf);
 121                 Dout(pn, 5, "loop 1: buf = %s, htype= %d/%s\n", buf, htype, header[htype].tag);
 122                 if (htype == H_CLEN) {
 123                         if (!sending) {
 124                                 savehdrs(buf,htype);
 125                         }
 126                         if ((hptr = hdrlines[H_CLEN].head) !=
 127                             (struct hdrs *)NULL) {
 128                                 clen = atol (hptr->value);
 129                         }
 130                 }
 131                 if (type == ZAP) {
 132                         if (htype != FALSE) {
 133                                 pushrest = (lastc != '\n');
 134                                 continue;
 135                         }
 136                         /* end of header.  Print non-blank line and bail. */
 137                         Dout(pn, 5, "ZAP end header; n=%d, buf[0] = %d\n", n, buf[0]);
 138                         if (buf[0] != '\n') {
 139                                 if (fwrite(buf,1,n,f) != n) {
 140                                         sav_errno = errno;
 141                                         return(FALSE);
 142                                 }
 143                         } else {
 144                                 n = 0;
 145                         }
 146                         break;
 147                 }
 148                 /* Copy From line appropriately */
 149                 if (fwrite(buf,1,n-1,f) != n-1)  {
 150                         sav_errno = errno;
 151                         return(FALSE);
 152                 }
 153                 if (lastc != '\n') {
 154                         if (fwrite(&lastc,1,1,f) != 1) {
 155                                 sav_errno = errno;
 156                                 return(FALSE);
 157                         }
 158                         continue;
 159                 }
 160                 switch(type) {
 161                         case REMOTE:
 162                                 if (fprintf(f, rmtmsg, thissys) < 0)
 163                                 {
 164                                         sav_errno = errno;
 165                                         return(FALSE);
 166                                 }
 167                                 
 168                                 break;
 169 
 170                         case TTY:
 171                         case ORDINARY:
 172                         default:
 173                                 if (fprintf(f, "\n") < 0)
 174                                 {
 175                                         sav_errno = errno;
 176                                         return(FALSE);
 177                                 }
 178                                 break;
 179                 }
 180                 if ((error > 0) && (dflag == 1)) {
 181                         Dout(pn, 3, "before gendeliv(), uval = '%s'\n", uval);
 182                         gendeliv(f, dflag, uval);
 183                         if (!(ckdlivopts(H_TCOPY, (int*)0) & RETURN)) {
 184                                 rtrncont = 0;
 185                         } else {
 186                                 /* Account for content-type info */
 187                                 /* of returned msg */
 188                                 if (fprintf(f, "%s %s\n", header[H_CTYPE].tag,
 189                                     (let[letnum].text == TRUE ? "text/plain" : "application/octet-stream")) < 0)
 190                                 {
 191                                         sav_errno = errno;
 192                                         return(FALSE);
 193                                 }
 194 
 195                                 /* Compute Content-Length of what's being */
 196                                 /* returned... */
 197                                 i = k;
 198                                 /* Account for H_AFWDFROM, H_AFWDCNT, */
 199                                 /* H_TCOPY, or H_RECEIVED lines which may */
 200                                 /* be added later */
 201                                 if (affcnt > 0) {
 202                                         sprintf(wbuf, "%d", affcnt);
 203                                         i += (affbytecnt
 204                                                 + strlen(header[H_AFWDCNT].tag)
 205                                                 + strlen(wbuf) + 2);
 206                                 }
 207                                 if (orig_tcopy) {
 208                                     if ((hptr = hdrlines[H_TCOPY].head) !=
 209                                                         (struct hdrs *)NULL) {
 210                                         i +=
 211                                           strlen(hdrlines[H_TCOPY].head->value);
 212                                     }
 213                                 }
 214                                 if ((hptr = hdrlines[H_RECEIVED].head) !=
 215                                                         (struct hdrs *)NULL) {
 216                                     i += rcvbytecnt;
 217                                 }
 218                                 /* Add in strlen of MIME-Version:, */
 219                                 /* Content-Length: and Content-Type: */
 220                                 /* values for msg being returned... */
 221                                 if ((hptr = hdrlines[H_MIMEVERS].head) !=
 222                                                         (struct hdrs *)NULL) {
 223                                     i += strlen(hdrlines[H_MIMEVERS].head->value);
 224                                 }
 225                                 if ((hptr = hdrlines[H_CTYPE].head) !=
 226                                                         (struct hdrs *)NULL) {
 227                                     i += strlen(hdrlines[H_CTYPE].head->value);
 228                                 }
 229                                 if ((hptr = hdrlines[H_CLEN].head) !=
 230                                                         (struct hdrs *)NULL) {
 231                                     i += strlen(hdrlines[H_CLEN].head->value);
 232                                 }
 233                                 if (fprintf(f, "%s %ld\n", header[H_CLEN].tag, i) < 0)
 234                                 {
 235                                         sav_errno = errno;
 236                                         return(FALSE);
 237                                 }
 238                         }
 239                         if (fprintf(f, "\n") < 0)
 240                         {
 241                                 sav_errno = errno;
 242                                 return(FALSE);
 243                         }
 244                 }
 245                 if (fflush(f))
 246                 {
 247                         sav_errno = errno;
 248                         return(FALSE);
 249                 }
 250                 
 251                 break;
 252         }
 253         /* if not ZAP, copy balance of header */
 254         n = 0;
 255         if ((type != ZAP) && rtrncont)
 256                 while (k>0 || n>0) {
 257                         if ((n > 0) && !suppress) {
 258                                 if (print_from_struct == TRUE) {
 259                                         if (printhdr (type, htype, hptr, f) < 0) {
 260                                                 return (FALSE);
 261                                         }
 262                                 } else {
 263                                     if (sel_disp(type, htype, buf) >= 0) {
 264                                         if (fwrite(buf,1,n,f) != n)  {
 265                                                 sav_errno = errno;
 266                                                 return(FALSE);
 267                                         }
 268                                     }
 269                                 }
 270                                 if (htype == H_DATE) {
 271                                         dumprcv(type, htype,&didrcvlines,&suppress,f);
 272                                         dumpaff(type, htype,&didafflines,&suppress,f);
 273                                 }
 274                         }
 275                         if (k <= 0) {
 276                                 /* Can only get here if k=0 && n>0, which occurs */
 277                                 /* in a message with header lines but no content. */
 278                                 /* If we haven't already done it, force out any */
 279                                 /* H_AFWDFROM or H_RECEIVED lines */
 280                                 dumprcv(type, -1,&didrcvlines,&suppress,f);
 281                                 dumpaff(type, -1,&didafflines,&suppress,f);
 282                                 break;
 283                         }
 284                         num = ((k < sizeof(buf)) ? k+1 : sizeof(buf));
 285                         if (fgets (buf, num, tmpf) == NULL) {
 286                                 return (FALSE);
 287                         }
 288                         n = strlen (buf);
 289                         k -= n;
 290                         lastc = buf[n-1];
 291 
 292                         if (pushrest) {
 293                                 pushrest = (lastc != '\n');
 294                                 continue;
 295                         }
 296                         sav_suppress = suppress;
 297                         suppress = FALSE;
 298                         print_from_struct = FALSE;
 299                         sav_htype = htype;
 300                         htype = isheader (buf, &ctf);
 301                         Dout(pn, 5, "loop 2: buf = %s, htype= %d/%s\n", buf, htype, header[htype].tag);
 302                         /* The following order is defined in the MTA documents. */
 303                         switch (htype) {
 304                         case H_CONT:
 305                             if (sending) {
 306                                 suppress = sav_suppress;
 307                             }
 308                             continue;
 309                         case H_TCOPY:
 310                         case H_MIMEVERS:
 311                         case H_CTYPE:
 312                         case H_CLEN:
 313                                 if (!sending) {
 314                                         savehdrs(buf,htype);
 315                                 }
 316                                 hptr = hdrlines[htype].head;
 317                                 if (htype == H_CLEN) {
 318                                         clen = atol (hptr->value);
 319                                 }
 320                                 /*
 321                                  * Use values saved in hdrlines[] structure
 322                                  * rather than what was read from tmp file.
 323                                  */
 324                                 print_from_struct = TRUE;
 325                                 /* FALLTHROUGH */
 326                         case H_EOH:
 327                         case H_AFWDFROM:
 328                         case H_AFWDCNT:
 329                         case H_RECEIVED:
 330                                 dumprcv(type, htype,&didrcvlines,&suppress,f);
 331                                 dumpaff(type, htype,&didafflines,&suppress,f);
 332                                 continue;       /* next header line */
 333                         default:
 334                                 pushrest = (lastc != '\n');
 335                                 continue;       /* next header line */
 336                         case FALSE:     /* end of header */
 337                                 break;
 338                         }
 339 
 340                         /* Found the blank line after the headers. */
 341                         if (n > 0) {
 342                                 if (fwrite(buf,1,n,f) != n)  {
 343                                         sav_errno = errno;
 344                                         return(FALSE);
 345                                 }
 346                         }
 347 
 348                         Dout(pn, 3,", let[%d].text = %s\n",
 349                                 letnum, (let[letnum].text ? "TRUE" : "FALSE"));
 350 
 351                         if ((type == TTY) && (let[letnum].text == FALSE) && !pflg) {
 352                                 if (fprintf (f, "\n%s\n", binmsg) < 0)
 353                                 {
 354                                         sav_errno = errno;
 355                                         return(FALSE);
 356                                 }
 357                                 return (TRUE);
 358                         }
 359 
 360                         if (n == 1 && buf[0] == '\n') {
 361                                 n = 0;
 362                         }
 363                         break;
 364                 }
 365 
 366         Dout(pn, 1, "header processed, clen/k/n = %ld/%ld/%d\n", clen, k, n);
 367 
 368         if (clen >= 0) {
 369                 if (((clen - n) == k) || ((clen - n) == (k - 1))) {
 370                         k = clen - n;
 371                 } else {
 372                         /* probable content-length mismatch. show it ALL! */
 373                         Dout(pn, 1, "clen conflict. using k = %ld\n", k);
 374                 }
 375         }
 376 
 377         /* copy balance of message */
 378         if (rtrncont)
 379                 while (k > 0) {
 380                         num = ((k < sizeof(buf)) ? k : sizeof(buf));
 381                         if ((n = fread (buf, 1, num, tmpf)) <= 0) {
 382                                 Dout(pn, 1, "content-length mismatch. return(FALSE)\n");
 383                                 return(FALSE);
 384                         }
 385                         k -= n;
 386                         if (fwrite(buf,1,n,f) != n)  {
 387                                 sav_errno = errno;
 388                                 return(FALSE);
 389                         }
 390                 }
 391 
 392         Dout(pn, 3, "body processed, k=%ld\n", k);
 393 
 394         if (rtrncont && type != ZAP && type != REMOTE) {
 395                 if (fwrite("\n",1,1,f) != 1)  {
 396                         sav_errno = errno;
 397                         return(FALSE);
 398                 }
 399         }
 400 
 401         return(TRUE);
 402 }