pop_bull.c
上传用户:dayuan858
上传日期:2007-01-04
资源大小:194k
文件大小:10k
源码类别:

网络编程

开发平台:

Unix_Linux

  1. /*
  2.  * Copyright (c) 1997 by Qualcomm Incorporated.
  3.  */
  4. /*
  5.  * bullcopy
  6.  *
  7.  */
  8. #if HAVE_CONFIG_H
  9. # include <config.h>
  10. #endif
  11. #include <stdio.h>
  12. #include <pwd.h>
  13. #if HAVE_SYS_FILE_H
  14. # include <sys/file.h>
  15. #endif
  16. #if HAVE_DIRENT_H
  17. # include <dirent.h>
  18. # define NAMLEN(dirent) strlen((dirent)->d_name)
  19. #else
  20. # define dirent direct
  21. # define NAMLEN(dirent) (dirent)->d_namlen
  22. # if HAVE_SYS_NDIR_H
  23. #  include <sys/ndir.h>
  24. # endif
  25. # if HAVE_SYS_DIR_H
  26. #  include <sys/dir.h>
  27. # endif
  28. # if HAVE_NDIR_H
  29. #  include <ndir.h>
  30. # endif
  31. #endif
  32. #ifndef HAVE_BCOPY
  33. # define bcopy(src,dest,len) (void) (memcpy(dest,src,len))
  34. #endif
  35. #include <ctype.h>
  36. #include <sys/types.h>
  37. #include <popper.h>
  38. #include <flock.h>
  39. static int sequence = 0;
  40. static time_t timestamp;
  41. static char *errmesg = "Unable to copy Bulletin %s to pop dropbox %s (%d)";
  42. typedef struct _file_list file_list;
  43. struct _file_list {
  44.     char *bull_name;
  45.     long bull_value;
  46.     file_list *next;
  47. };
  48. /*
  49.  * List in the ascending order of the bulletin value
  50.  */
  51. file_list *
  52. insert_list(p, head, name)
  53. POP *p;
  54. file_list *head;
  55. char *name;
  56. {
  57.     long new_bull;
  58.     file_list *new_rec, *current;
  59.     new_bull = atol(name);
  60.     new_rec = (file_list *)malloc(sizeof(file_list));
  61.     new_rec->next = NULL;
  62.     new_rec->bull_value = new_bull;
  63.     new_rec->bull_name = (char *)malloc(strlen(name) + 1);
  64.     strcpy(new_rec->bull_name, name);
  65.     current = head;
  66.     if (!head) {
  67. return(new_rec);
  68.     } else {
  69. if (head->bull_value > new_bull) {
  70.     new_rec->next = head;
  71.     head = new_rec;
  72.     return(head);
  73. }
  74.     }
  75.     while (current->next) {
  76. if (current->next->bull_value > new_bull)
  77.     break;
  78. current = current->next;
  79.     }
  80.     new_rec->next = current->next;
  81.     current->next = new_rec;
  82.     return(head);
  83. }
  84. /*
  85.  *  pop_bull: Append any new bulletins to the end of the user's
  86.  *  temporary maildrop.
  87.  */
  88. pop_bull (p, pwp)                  
  89. POP *p;
  90. struct passwd *pwp;
  91. {
  92.    char popBullName[256];
  93.    FILE *popBull;
  94.    DIR *dirp;
  95.    file_list *list = NULL;
  96.    struct dirent *dp;
  97.    long maxBullNumber = 0;
  98.    long bullNumber;
  99.    long lastBullSent;
  100.    char buffer[MAXMSGLINELEN];
  101.    int res;
  102.    int bullcount = 0;
  103.    int save_count;
  104. #ifdef BULLDB
  105.    datum bull_count;
  106.    datum name;
  107. #endif
  108.    /* Construct full path name of .popbull file. */
  109.    sprintf(popBullName, "%s/.popbull", pwp->pw_dir);
  110.    /* Scan bulletin directory and compute the maximum current
  111.       bulletin number. */
  112.    dirp = opendir(p->bulldir);
  113.    if (dirp == NULL) {
  114.       pop_log(p, POP_PRIORITY,
  115.          "Unable to open bulletin directory '%s'. (%d)", p->bulldir, errno);
  116.       return POP_FAILURE;
  117.    }
  118.    while ((dp = readdir(dirp)) != NULL) {
  119.       if (!isdigit(*dp->d_name)) continue;
  120.       bullNumber = atol(dp->d_name);
  121.       if (bullNumber > maxBullNumber) maxBullNumber = bullNumber;
  122.       list = insert_list(p, list, dp->d_name);
  123.    }
  124.    closedir(dirp); 
  125.    timestamp = time(0);
  126.    /* Open the user's .popbull file and read the number of the last
  127.       bulletin sent to this user. If the file doesn't exist, create
  128.       it and seed it with the current max bulletin number. Note that
  129.       new users do not get sent old bulletins. */
  130. #ifdef BULLDB
  131.    name.dptr = p->user;
  132.    name.dsize = strlen(p->user) + 1;
  133. #ifdef GDBM
  134.    bull_count = gdbm_fetch(p->bull_db, name);
  135. #else
  136.    bull_count = dbm_fetch(p->bull_db, name);
  137. #endif
  138.    if (bull_count.dptr == NULL) {
  139.       /* If the database does not have a value, check the users .popbull
  140.        * file.  If it's not empty, then use the value there, otherwise,
  141.        * create a new value.
  142.        */
  143.        popBull = fopen(popBullName, "r");
  144.        if ((popBull == NULL) || (fgets(buffer,MAXMSGLINELEN,popBull) == NULL) ||
  145.             !isdigit(*buffer)) {
  146.    if ((lastBullSent = (maxBullNumber - NEWBULLCNT)) < 0)
  147.       lastBullSent = 0;
  148.        } else {
  149.    lastBullSent = atol(buffer);
  150.        }
  151.        if (popBull)
  152.    fclose(popBull);
  153.        bull_count.dptr = (char *)&lastBullSent;
  154.        bull_count.dsize = sizeof(lastBullSent);
  155. #ifdef GDBM
  156.        gdbm_store(p->bull_db, name, bull_count, GDBM_REPLACE);
  157. #else
  158.        /* Block while waiting for a lock to update the entry */
  159.        if (flock(dbm_dirfno(p->bull_db), LOCK_EX) == -1)
  160.   return(pop_msg(p, POP_FAILURE, "Bulletin database lock failed"));
  161.        dbm_store(p->bull_db, name, bull_count, DBM_REPLACE);
  162. #endif
  163.        flock(dbm_dirfno(p->bull_db), LOCK_UN);
  164.        if (NEWBULLCNT <= 0) {
  165.      return POP_SUCCESS;
  166.        }
  167.    } 
  168.    else
  169. bcopy(bull_count.dptr, &lastBullSent, bull_count.dsize);
  170. #else
  171.    popBull = fopen(popBullName, "r");
  172.    if ((popBull == NULL) || (fgets(buffer, MAXMSGLINELEN, popBull) == NULL) ||
  173.        !isdigit(*buffer)) {
  174.        if (popBull != NULL) fclose(popBull);
  175.        popBull = fopen(popBullName, "w");
  176.        if (popBull == NULL) {
  177.    pop_log(p, POP_PRIORITY, "Unable to create .popbull file (%d)", errno);
  178.    return POP_FAILURE;
  179.        }
  180.       if ((lastBullSent = (maxBullNumber - NEWBULLCNT)) < 0)
  181.   lastBullSent = 0;
  182.       fprintf(popBull, "%ldn", lastBullSent);
  183.       fclose(popBull);
  184.       if (NEWBULLCNT <= 0)
  185.   return POP_SUCCESS;
  186.    } 
  187.    else lastBullSent = atol(buffer);
  188. #endif /* BULLDB */
  189.    /* If there aren't any new bulletins for this user, return. */
  190.    if (lastBullSent >= maxBullNumber) {
  191.        return POP_SUCCESS;
  192.    }
  193.    (void) chmod(popBullName, 0600);   /* Only needs to be read by me */
  194.    /* Append the new bulletins to the end of the user's temporary 
  195.       mail drop. */
  196.    res = POP_SUCCESS;
  197.    save_count = p->msg_count;
  198.    while (list) {
  199.        if (list->bull_value > lastBullSent)
  200.            if ((res = CopyOneBull(list->bull_name, p)) != POP_SUCCESS) {
  201.       p->msg_count = save_count;
  202.       break;
  203.    }
  204. list = list->next;
  205.    }
  206.    if (res == POP_SUCCESS) {
  207. #ifdef BULLDB
  208.        bull_count.dptr = (char *)&maxBullNumber;
  209.        bull_count.dsize = sizeof(maxBullNumber);
  210.        if (flock(dbm_dirfno(p->bull_db), LOCK_EX) == -1) {
  211.    p->msg_count = save_count;
  212.   return(pop_msg(p, POP_FAILURE, "Bulletin database lock failed"));
  213.        }
  214. #ifdef GDBM
  215.        gdbm_store(p->bull_db, name, bull_count, GDBM_REPLACE);
  216. #else
  217.        dbm_store(p->bull_db, name, bull_count, DBM_REPLACE);
  218. #endif
  219.        flock(dbm_dirfno(p->bull_db), LOCK_UN);
  220. #else
  221.        /* Update the user's .popbull file. */
  222.        popBull = fopen(popBullName, "w");
  223.        if (popBull == NULL) {
  224.    p->msg_count = save_count;
  225.    pop_log(p, POP_PRIORITY, "Unable to open .popbull file. (%d)", errno);
  226.    return POP_FAILURE;
  227.        }
  228.        fprintf(popBull, "%ldn", maxBullNumber);
  229.        fclose(popBull); 
  230. #endif
  231.     }
  232.    return(res);
  233. }
  234. extern int newline;
  235. /*
  236.  *  CopyOneBull: Append a single bulletin file to the end of the
  237.  *  temporary maildrop file.
  238.  */
  239. CopyOneBull(name, p)
  240. char *name;
  241. POP *p;
  242. {
  243.     FILE *bull;
  244.     char buffer[MAXMSGLINELEN];
  245.     int in_header = 1;
  246.     int first_line = 1;
  247.     int nchar;
  248.     int msg_num;
  249.     int receivedhdrs = 0;
  250.     char bullName[256];
  251.     MsgInfoList *mp; /* Pointer to message info list */
  252.     msg_num = p->msg_count;
  253.     p->msg_count = (((p->msg_count - 1) / ALLOC_MSGS) + 1) * ALLOC_MSGS;
  254.     sprintf(bullName, "%s/%s", p->bulldir, name);
  255.     bull = fopen(bullName, "r");
  256.     if (bull == NULL) {
  257.        pop_log(p, POP_PRIORITY,
  258.       "Unable to open bulletin file %s (%d)", name, errno);
  259.        return POP_FAILURE;
  260.     }
  261.     newline = 1;
  262.     if ((fgets(buffer, MAXMSGLINELEN, bull) != NULL) && !(isfromline(buffer))) {
  263. pop_log(p, POP_PRIORITY,
  264.     "Bulletin %s does not start with a valid "From " separator",name);
  265. fclose(bull);
  266. return POP_FAILURE;
  267.     }
  268.     /* Just and appended message, no Status or UIDL updates here */
  269. #ifndef NO_STATUS
  270.     p->dirty = 1;
  271. #endif
  272.     mp = p->mlp + msg_num - 1;
  273.     if (++msg_num > p->msg_count) {
  274. p->mlp=(MsgInfoList *) realloc(p->mlp,
  275.     (p->msg_count += ALLOC_MSGS)*sizeof(MsgInfoList));
  276. if (p->mlp == NULL) {
  277.     p->msg_count = 0;
  278.     return pop_msg (p,POP_FAILURE,
  279.      "Bull: Can't build message list for '%s': Out of memory",
  280.      p->user);
  281. }
  282. mp = p->mlp + msg_num - 2;
  283.     }
  284.     ++mp;
  285.     mp->number = msg_num;
  286.     mp->length = 0;
  287.     mp->lines = 0;
  288.     mp->body_lines = 0;
  289.     mp->offset = ftell(p->drop);
  290.     mp->del_flag = FALSE;
  291.     mp->retr_flag = FALSE;
  292.     if (fputs(buffer, p->drop) == EOF) {
  293. return(pop_msg(p, POP_FAILURE, errmesg, name, p->temp_drop, errno));
  294.     }
  295.     p->drop_size += strlen(buffer);
  296.     mp->lines++;
  297.     sprintf(buffer, "X-UIDL: %ld.%05dn", timestamp, sequence);
  298.     if (fputs(buffer, p->drop) == EOF) {
  299. return(pop_msg(p, POP_FAILURE, errmesg, name, p->temp_drop, errno));
  300.     }
  301.     mp->length += strlen(buffer);
  302.     p->drop_size += strlen(buffer);
  303.     mp->lines++;
  304. #ifdef DEBUG
  305.     if(p->debug)
  306. pop_log(p,POP_DEBUG,
  307. "Bull msg %d being added to list, offset %d",
  308. mp->number, mp->offset);
  309. #endif
  310.     sprintf(buffer, "%ld.%05dn", timestamp, sequence++);
  311.     mp->uidl_str = (char *)strdup(buffer);
  312.     first_line = 0;
  313.     while (fgets(buffer, MAXMSGLINELEN, bull) != NULL) {
  314. nchar = strlen(buffer);
  315. if (in_header) { /* Header */
  316.     if (!strncasecmp(buffer, "X-UIDL:", 7)) {
  317. continue; /* Skip any UIDLs */
  318.     } else if (strncasecmp(buffer, "To:", 3) == 0) {
  319. sprintf(buffer,"To: %s@%sn", p->user, p->myhost);
  320. nchar = strlen(buffer);
  321.     } else if (strncasecmp(buffer, "Status:", 7) == 0) {
  322. continue;
  323.     } else if (*buffer == 'n') {
  324. in_header = 0;
  325. mp->body_lines = 0; /* Reset to zero when in the body */
  326.     }
  327. }
  328. mp->length += nchar;
  329. p->drop_size += nchar;
  330. mp->lines++;
  331. mp->body_lines++;
  332. if (fputs(buffer, p->drop) == EOF) {
  333.     return(pop_msg(p,POP_FAILURE,errmesg,name,p->temp_drop, errno));
  334. }
  335.     }
  336.     fflush(p->drop);
  337.     p->msg_count = msg_num;
  338.     fclose(bull);
  339. #ifdef DEBUG
  340.     if(p->debug && msg_num != 1)
  341. pop_log(p,POP_DEBUG,
  342. "Bull msg %d uidl %s at offset %d is %d octets long and has %u lines.",
  343. mp->number,mp->uidl_str,mp->offset,mp->length,mp->lines);
  344. #endif
  345.     return POP_SUCCESS;
  346. }