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