/* 3mailout.c
 * Public Domain
 *
 * contains functions to write a type 3 ASCII packet
 *
 * code as written is memory thrifty.  performance enhancements would involve
 * building the header in memory and writing in one operation.  note there is
 * no function for writing message text; this can too easily be accomplished
 * with a simple write().  note these functions always properly terminate the
 * packet (but seek back so next read overwrites terminator)
 *
 * there is no single user-callable function for this module.  too much
 * depends on how and in what form you get the message from the local
 * message base, and where and by what name you write packets for your
 * mailer.
 */

#include "3mail.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <io.h>
#include <fcntl.h>
#include <share.h>



void finish_3pktpartcr (int o3handle,int *error) {

  /* terminate a header */

  long pos;

  if(write(o3handle,"\r",2) < 2) *error = BADWRITE3;  /* \r + \0 */
  pos = tell(o3handle);
  if(pos) {               /* back up over terminating NUL */
    if(lseek(o3handle,pos - 1L,SEEK_SET) == -1L) *error = BADSEEK3;
  }
}



int write_3tag (int o3handle,char *tag,char *data, int *error) {

  /* write a tag + data line
   * handles tags without data and data without tags, too
   */

  char s[258] = "";
  int writlen = 0;

  if(tag && *tag) {
    strcpy(s,tag);
  }

  if(data && *data) {
    if(tag && *tag) strcat(s," ");
    strncat(s,data,255 - strlen(s));
  }

  strcat(s,"\r");

  writlen = write(o3handle,s,strlen(s));
  if(writlen == -1) *error = BADWRITE3;
  return writlen;
}


int write_3tags (int o3handle,TAG3 *head,int *error) {

  /* write a linked list of tag+data lines */

  TAG3 *info = head,*next;

  while(info) {
    next = info->next;
    if(write_3tag(o3handle,info->tag,info->data,error) < 1) {
      return -1;
    }
  }
  return 0;
}


int write_3pkthdr (int o3handle,PHDR3 *cpkt,int *error) {

  /* write a complete PHDR3 packet header structure to disk */

  int writlen = 0;

  *error = NOERR3;
  writlen += write(o3handle,ASCII3ID"\r",7);
  writlen += write_3tag(o3handle,NULL,cpkt->from,error);
  writlen += write_3tag(o3handle,NULL,cpkt->to,error);
  writlen += write_3tag(o3handle,NULL,cpkt->creator,error);
  writlen += write_3tag(o3handle,NULL,cpkt->pword,error);
  writlen += write_3tag(o3handle,NULL,cpkt->area,error);
  writlen += write_3tags(o3handle,cpkt->head,error);
  finish_3pktpartcr(o3handle,error);
  return writlen;
}


int wopen_3pkt (int o3handle,char *fname,PHDR3 *cpkt,int *error) {

  /* open a type 3 packet for output, write header if new packet
   * fname = name of packet file
   * cpkt = packet header (written if new packet)
   * *error = error code return
   * o3handle = handle to current packet (or -1 for none)
   * returns handle to packet
   */

  static int last = -1;
  long       pos;

  *error = NOERR3;
  if(o3handle != -1 && o3handle != last) {  /* avoid opening already open file
                                               since open is a slow operation
                                               on many systems */
    close(o3handle);
    o3handle = -1;
  }

  if(o3handle == -1) {
    o3handle = sopen(fname,O_RDWR | O_BINARY | O_CREAT,SH_DENYWR,S_IWRITE);
    if(o3handle != -1) {           /* opened; new packet? */
      lseek(o3handle,0L,SEEK_END);
      if((pos = tell(o3handle)) == 0L) {   /* yes; write header */
        write_3pkthdr(o3handle,cpkt,error);
      }
      else {                            /* no, pos for output */
        if(lseek(o3handle,pos - 1L,SEEK_SET) == -1L) *error = BADSEEK3;
      }
    }
    else *error = NOOPEN3;  /* couldn't open */
  }

  return o3handle;
}


int wclose_3pkt (int o3handle) {    /* close packet */

  if(o3handle != -1) close(o3handle); /* close if good handle */
  o3handle = -1;                      /* in case you make it global... */
  return o3handle;
}


int write_3msghdr (int o3handle,MHDR3 *cmsg,int *error) {

  /* write a complete MHDR3 message header structure to disk */

  int writlen = 0;

  *error = NOERR3;
  writlen += write_3tag(o3handle,NULL,cmsg->from,error);
  writlen += write_3tag(o3handle,NULL,cmsg->to,error);
  writlen += write_3tag(o3handle,NULL,cmsg->subj,error);
  writlen += write_3tag(o3handle,NULL,cmsg->date,error);
  writlen += write_3tag(o3handle,NULL,cmsg->area,error);
  writlen += write_3tag(o3handle,NULL,cmsg->id,error);
  writlen += write_3tag(o3handle,NULL,cmsg->ref,error);
  writlen += write_3tags(o3handle,cmsg->head,error);
  finish_3pktpartcr(o3handle,error);
  return writlen;
}
