/*
 * bullcopy
 *
 */

#include <stdio.h>
#include <pwd.h>
#ifdef PYRAMID
#include <sys/types.h>
#include <sys/dir.h>
#else
#include <dirent.h>
#endif
#include <ctype.h>
#include "popper.h"

/*
 *  pop_bull: Append any new bulletins to the end of the user's
 *  temporary maildrop.
 */

pop_bull (p, pwp)                  
POP *p;
struct passwd *pwp;
{
   char popBullName[256];
   FILE *popBull;
   DIR *dirp;
#ifdef PYRAMID
   struct direct *dp;
#else
   struct dirent *dp;
#endif
   long maxBullNumber = 0;
   long bullNumber;
   long lastBullSent;
   char buffer[MAXMSGLINELEN];
   int res;
   int save_count;

   /* Construct full path name of .popbull file. */
   sprintf(popBullName, "%s/.popbull", pwp->pw_dir);

   /* Scan bulletin directory and compute the maximum current
      bulletin number. */
   dirp = opendir(p->bulldir);
   if (dirp == NULL) {
      pop_log(p, POP_PRIORITY,
         "Unable to open bulletin directory.");
      return POP_FAILURE;
   }


   while ((dp = readdir(dirp)) != NULL) {
      if (!isdigit(*dp->d_name)) continue;
      bullNumber = atol(dp->d_name);
      if (bullNumber > maxBullNumber) maxBullNumber = bullNumber;
   }
   closedir(dirp); 

   /* Open the user's .popbull file and read the number of the last
      bulletin sent to this user. If the file doesn't exist, create
      it and seed it with the current max bulletin number. Note that
      new users do not get sent old bulletins. */
   popBull = fopen(popBullName, "r");
   if (popBull == NULL) {
      popBull = fopen(popBullName, "w");
      if (popBull == NULL) {
         pop_log(p, POP_PRIORITY,
            "Unable to create .popbull file");
         return POP_FAILURE;
      }
      fprintf(popBull, "%ld\n", maxBullNumber);
      fclose(popBull);
      return POP_SUCCESS;
   } else {
      if (fgets(buffer, MAXMSGLINELEN, popBull) == NULL ||
         !isdigit(*buffer)) 
      {
         fclose(popBull);
         return POP_SUCCESS;
      }
      lastBullSent = atol(buffer);
      fclose(popBull);
   }

   /* If there aren't any new bulletins for this user, return. */
   if (lastBullSent >= maxBullNumber) return POP_SUCCESS;


   /* Append the new bulletins to the end of the user's temporary 
      mail drop. */
   dirp = opendir(p->bulldir);
   if (dirp == NULL) {
      pop_log(p, POP_PRIORITY,
         "Unable to open bulletin direcotry.");
      return POP_FAILURE;
   }

   res = POP_SUCCESS;
   save_count = p->msg_count;


   while ((dp = readdir(dirp)) != NULL) {
      if (!isdigit(*dp->d_name)) continue;
      bullNumber = atol(dp->d_name);
      if (bullNumber > lastBullSent)
         if ((res = CopyOneBull(dp->d_name, p)) != POP_SUCCESS) {
	    p->msg_count = save_count;
	    break;
	 }
   }
   closedir(dirp);

   if (res == POP_SUCCESS) {
       /* Update the user's .popbull file. */
       popBull = fopen(popBullName, "w");
       if (popBull == NULL) {
	  pop_log(p, POP_PRIORITY,
	     "Unable to open .popbull file.");
	  return POP_FAILURE;
       }
       fprintf(popBull, "%ld\n", maxBullNumber);
       fclose(popBull); 
    }

    return(res);
}

/*
 *  CopyOneBull: Append a single bulletin file to the end of the
 *  temporary maildrop file.
 */

CopyOneBull(name, p)
char *name;
POP *p;
{
   FILE *bull;
   char buffer[MAXMSGLINELEN];
   int in_header = 1;
   int first_line = 1;
   int uidlfound = 0;
   int nchar;
   int msg_num;
   char bullName[256];
   MsgInfoList *mp;			/* Pointer to message info list */

   msg_num = p->msg_count;
   p->msg_count = (((p->msg_count - 1) / ALLOC_MSGS) + 1) * ALLOC_MSGS;

   sprintf(bullName, "%s/%s", p->bulldir, name);
   bull = fopen(bullName, "r");
   if (bull == NULL) {
      pop_log(p, POP_PRIORITY,
         "Unable to open bulletin file %s", name);
      return POP_FAILURE;
   }

   while (fgets(buffer, MAXMSGLINELEN, bull) != NULL) {
      nchar = strlen(buffer);

      if (first_line == 1 && strncasecmp(buffer, "From ", 5) != 0) {
         pop_log(p, POP_PRIORITY,
            "Bulletin %s does not start with \"From \"", name);
         fclose(bull);
         return POP_FAILURE;
      } else if (first_line) {
	 mp = p->mlp + msg_num - 1;

         if (++msg_num > p->msg_count) {
           p->mlp=(MsgInfoList *) realloc(p->mlp,
                (p->msg_count += ALLOC_MSGS)*sizeof(MsgInfoList));
           if (p->mlp == NULL) {
               p->msg_count = 0;
               return pop_msg (p,POP_FAILURE,
                       "Bull: Can't build message list for '%s': Out of memory",
			      p->user);
           }

	   mp = p->mlp + msg_num - 2;
         }

#ifdef DEBUG
          if(p->debug && msg_num != 1)
              pop_log(p,POP_DEBUG,
                   "Bull msg %d at offset %d is %d octets long and has %u lines.",
                        mp->number,mp->offset,mp->length,mp->lines);
#endif

         ++mp;
         mp->number = msg_num;
         mp->length = 0;
         mp->lines = 0;
         mp->offset = ftell(p->drop);
         mp->del_flag = FALSE;
         mp->retr_flag = FALSE;
#ifdef DEBUG
         if(p->debug)
              pop_log(p,POP_DEBUG, "Bull msg %d being added to list, offset %d", mp->number, mp->offset);
#endif
      }

      first_line = 0;
      if (in_header) { /* Header */
         if (strncasecmp(buffer, "To:", 3) == 0) {
            fprintf(p->drop, "To: %s@%s\n", p->user, p->myhost);
            continue;
         } else if (strncasecmp(buffer, MSGUIDL, strlen(MSGUIDL)) == 0) {
	     uidlfound = 1;
	 } else if (strncasecmp(buffer, "Status:", 7) == 0) {
            continue;
         }
         if (*buffer == '\n') {
	     in_header = 0;

	     if (!uidlfound) {
	        sprintf(buffer,"%s %ld.%03d\n",MSGUIDL,p->session_time,p->uidl_seq++);
		if (fputs(buffer, p->drop) == EOF) {
                    return pop_msg (p,POP_FAILURE,
			    "Unable to copy bulletin file %s to pop dropbox %s",
                            name, p->temp_drop);
		}

	        mp->length += strlen(buffer);
	        p->drop_size += strlen(buffer);
	        mp->lines++;

	        strcpy(buffer, "\n");
	        nchar = 1;
	    }
	 }
      }

      mp->length += nchar;
      p->drop_size += nchar;
      mp->lines++;

      if (fputs(buffer, p->drop) == EOF) {
	  return(pop_msg(p, POP_FAILURE,
				"Unable to copy Bulletin %s to pop dropbox %s",
					name, p->temp_drop));
      }
   }

   fflush(p->drop);

   p->msg_count = msg_num;
   fclose(bull);
   return POP_SUCCESS;
}

