Logo Search packages:      
Sourcecode: yencode version File versions

ypost.c

/**************************************************************************************************
      $Header: /pub/cvsroot/yencode/src/ypost/ypost.c,v 1.5 2002/03/21 21:46:47 bboy Exp $

      Copyright (C) 2002  Don Moore <bboy@bboy.net>

      This program is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published by
      the Free Software Foundation; either version 2 of the License, or
      (at your option) any later version.

      This program is distributed in the hope that it will be useful,
      but WITHOUT ANY WARRANTY; without even the implied warranty of
      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      GNU General Public License for more details.

      You should have received a copy of the GNU General Public License
      along with this program; if not, write to the Free Software
      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
**************************************************************************************************/

#include "ypost.h"


int         opt_verbose = 1;                                      /* Should the program be verbose in its operation? */
int         opt_debug = 0;                                              /* Debug output? */

char        *opt_author = NULL;                                   /* Author name for posting */
int         opt_prompt_author = 0;                          /* Prompt for author? */
char        *opt_auth_user = NULL;                          /* Username for authentication */
char        *opt_auth_pass = NULL;                          /* Password for authentication */
int         opt_prompt_pass = 0;                                  /* Prompt for password? */
char        *opt_nntp_server = NULL;                        /* nntp server to use */
char        *opt_subject = NULL;                                  /* Subject prefix */
int         opt_prompt_subject = 0;                         /* Prompt for subject? */
char        *opt_comment = NULL;                                  /* Subject suffix */
int         opt_prompt_comment = 0;                         /* Prompt for comment? */
int         opt_timeout = -1;                                     /* Timeout for socket ops */
char        *opt_newsgroup = NULL;                          /* Newsgroup to post to */
int         opt_force = 0;                                              /* Post messages without confirming? */
int         opt_nosort = 0;                                       /* Do not sort input files */
int         opt_multipart_lines = -1;                       /* Number of lines for multipart messages */
int         opt_info = 0;                                               /* Hidden option for debugging, just outputs file info */
int         opt_retry_limit = -1;                           /* Max number of retries on failed post */
int         opt_message_id = 0;                                   /* Generate Message-ID: header when posting? */
int         opt_stdout = 0;                                       /* Output to stdout instead of a file? */

char        *opt_sender = NULL;                                   /* For header generation, not set directly */

int         opt_line_length = -1;                           /* Line length for posting */
int         opt_keep_paths = 0;                                   /* Keep relative path names? */
int         opt_overwrite = 0;                                    /* (not actually used by this program..) */

int         opt_resume_msg = 0;                                   /* Message number at which to restart */
crc32_t     opt_resume_crc = 0;                                   /* CRC value for posts, to ensure they are the same */

YENCFILE    **input_files = (YENCFILE **)NULL;  /* List of files to process */
int         num_input_files = 0;                                  /* Number of items in files */

/* Optional common support files */
int         opt_sfv = 0;                                                /* Create .SFV file? */
char        *opt_sfv_filename = (char *)NULL;   /* SFV filename */
int         opt_crc = 0;                                                /* Create .CRC file? */
char        *opt_crc_filename = (char *)NULL;   /* CRC filename */

char        *opt_sort_first = NULL;                         /* Sort these extensions first, comma separated list */

size_t      total_input_bytes = 0;                          /* Total number of input bytes overall */

int         part_current = 0,                                     /* Current part number of this part */
                  part_total = 0;                                       /* Total number of parts for this part */
int         file_current = 0,                                     /* Current file number overall */
                  file_total = 0;                                       /* Total number of files being posted */
int         total_messages = 0,                                   /* Total number of messages to post */
                  total_posted = 0;                                     /* Total number of messages posted so far */
crc32_t     total_crc = 0;                                              /* Total CRC of all messages to post */


static int  posting_started = 0;                            /* Has the posting started yet? */



/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      USAGE
      Display program usage information.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
void
usage(int status)
{
      if (status != EXIT_SUCCESS)
      {
            fprintf(stderr, _("Try `%s --help' for more information."), progname);
            fputs("\n", stderr);
      }
      else
      {
            printf(_("Usage: %s [OPTION]... FILE..."), progname);
            puts("");
      puts(_("Post file(s) to Usenet."));
            puts("");
//          puts("----------------------------------------------------------------------------78");
            puts(_("  -a, --author=NAME      use NAME as author when posting (or prompt)"));
            puts(_("  -c, --comment=COMMENT  suffix all subjects with COMMENT (or prompt)"));
            puts(_("  -d, --debug            output extra debugging information while running"));
            puts(_("  -f, --force            post messages without confirming"));
            puts(_("  -g, --group=NEWSGROUP  post messages to the newsgroup called GROUP"));
            puts(_("  -l, --line=LEN         output lines that are LEN bytes in length"));
            puts(_("  -m, --multipart=NUM    multipart posts contain NUM lines (default: 5000)"));
            puts(_("  -M, --message-id       generate Message-ID header field when posting"));
            puts(_("  -n, --nosort           post articles in the order specified; do not sort"));
            puts(_("  -p, --paths            maintain paths in input filenames"));
            puts(_("  -P, --pass=PASS        password for nntp authentication (or prompt)"));
            puts(_("  -q, --quiet            inhibit all messages written to the standard output"));
            puts(_("  -r, --retry=NUM        if a post fails, retry NUM times (default: 3)"));
            puts(_("  -R, --resume=MSG,CHK   resume failed post at MSG, optionally verify CHK"));
            puts(_("  -s, --subject=SUBJECT  prefix all subjects with SUBJECT (or prompt)"));
            puts(_("  -S, --server=ADDR      connect to nntp server at ADDR (hostname or IP)"));
            puts(_("  -t, --timeout=SECS     socket operations timeout after SECS (default: 60)"));
            puts(_("  -U, --user=USER        username for nntp authentication"));
            puts(_("      --crc=NAME         post CRC checksum file for all input files"));
            puts(_("      --sfv=NAME         post SFV checksum file for all input files"));
            puts(_("      --stdout           output messages to standard output instead of posting"));
            puts(_("      --help             display this help and exit"));
            puts(_("      --version          output version information and exit"));
            puts("");
            puts(_("Command line options always override options found in the configuration file."));
            puts("");
      puts(_("Report bugs to bugs@yencode.org."));
      }
      exit(status);
}
/*--- usage() -----------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      CMDLINE
      Process command line options.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
static void
cmdline(int argc, char **argv)
{
      int  optc, optindex;
      char *optstr;
      struct option const longopts[] =
      {
            {"author",              optional_argument,      NULL, 'a'},
            {"comment",             optional_argument,      NULL, 'c'},
            {"debug",               no_argument,                  NULL, 'd'},
            {"force",               no_argument,                  NULL, 'f'},
            {"group",               required_argument,      NULL, 'g'},
            {"line",                      required_argument,      NULL, 'l'},
            {"multipart",           required_argument,      NULL, 'm'},
            {"pass",                      optional_argument,      NULL, 'P'},
            {"paths",               no_argument,                  NULL, 'p'},
            {"quiet",               no_argument,                  NULL, 'q'},
            {"retry",               required_argument,      NULL, 'r'},
            {"server",              required_argument,      NULL, 'S'},
            {"subject",             optional_argument,      NULL, 's'},
            {"timeout",             required_argument,      NULL, 't'},
            {"user",                      required_argument,      NULL, 'U'},
            {"sfv",                       optional_argument,      NULL, 0},
            {"stdout",              no_argument,                  NULL, 0},
            {"crc",                       optional_argument,      NULL, 0},
            {"resume",              required_argument,      NULL, 'R'},
            {"help",                      no_argument,                  NULL, 0},
            {"version",             no_argument,                  NULL, 0},
            {"info",                      no_argument,                  NULL, 0},

            {NULL, 0, NULL, 0}
      };

      optstr = getoptstr(longopts);
      while ((optc = getopt_long(argc, argv, optstr, longopts, &optindex)) != -1)
      {
            switch (optc)
            {
                  case 0:
                        {
                              const char *opt = longopts[optindex].name;

                              if (!strcmp(opt, "version"))                                                  // --version
                              {
                                    printf("%s - " PACKAGE " " VERSION "\n", short_progname);
                                    exit(EXIT_SUCCESS);
                              }
                              else if (!strcmp(opt, "help"))                                                // --help
                                    usage(EXIT_SUCCESS);
                              else if (!strcmp(opt, "sfv"))                                                 // --sfv
                              {
                                    opt_sfv = 1;
                                    opt_sfv_filename = optarg;
                              }
                              else if (!strcmp(opt, "crc"))                                                 // --crc
                              {
                                    opt_crc = 1;
                                    opt_crc_filename = optarg;
                              }
                              else if (!strcmp(opt, "info"))                                                // --info
                                    opt_info = 1;
                              else if (!strcmp(opt, "stdout"))                                              // --stdout
                                    opt_stdout = 1;
                        }
                        break;

                  case 'a':                                                                                                   // -a, --author=AUTHOR
                        if (optarg)
                              opt_author = xstrdup(optarg);
                        else
                              opt_prompt_author = 1;
                        break;

                  case 'c':                                                                                                   // -c, --comment=COMMENT
                        if (optarg)
                              opt_comment = xstrdup(optarg);
                        else
                              opt_prompt_comment = 1;
                        break;

                  case 'd':                                                                                                   // -d, --debug
                        opt_debug = opt_verbose = 1;
                        break;

                  case 'f':                                                                                                   // -f, --force
                        opt_force = 1;
                        break;

                  case 'g':                                                                                                   // -g, --group=GROUP
                        opt_newsgroup = xstrdup(optarg);
                        break;

                  case 'l':                                                                                                   // -l, --line
                        opt_line_length = atoi(optarg);
                        if (opt_line_length > 254)
                              Err(_("line lengths greater than 254 are not allowed by the yEnc specification"));
                        break;

                  case 'm':                                                                                                   // -m, --multipart=LINES
                        opt_multipart_lines = atoi(optarg);
                        break;

                  case 'M':                                                                                                   // -M, --message-id
                        opt_message_id = 1;
                        break;

                  case 'p':                                                                                                   // -p, --paths
                        opt_keep_paths = 1;
                        break;

                  case 'P':                                                                                                   // -P, --pass=PASS
                        if (optarg)
                              opt_auth_pass = xstrdup(optarg);
                        else
                              opt_prompt_pass = 1;
                        break;

                  case 'q':                                                                                                   // -q, --quiet
                        opt_debug = opt_verbose = 0;
                        break;

                  case 'r':                                                                                                   // -r, --retry=NUM
                        opt_retry_limit = atoi(optarg);
                        break;

                  case 'R':                                                                                                   // -R, --resume
                        {
                              char *c = strchr(optarg, ',');

                              if (c)
                              {
                                    *(c++) = '\0';
                                    opt_resume_crc = (crc32_t)strtoul(c, (char **)NULL, 16);
                              }
                              opt_resume_msg = atoi(optarg);
                        }
                        break;

                  case 's':                                                                                                   // -s, --subject=SUBJ
                        if (optarg)
                              opt_subject = xstrdup(optarg);
                        else
                              opt_prompt_subject = 1;
                        break;

                  case 'S':                                                                                                   // -S, --server=SERV
                        opt_nntp_server = xstrdup(optarg);
                        break;

                  case 't':                                                                                                   // -t, --timeout=SECS
                        opt_timeout = atoi(optarg);
                        break;

                  case 'U':                                                                                                   // -U, --user=USER
                        opt_auth_user = xstrdup(optarg);
                        break;

                  default:
                        usage(EXIT_FAILURE);
            }
      }

      /* Set these options for the routines in "error.c" in the library */
      err_debug = opt_debug;
      err_verbose = opt_verbose;

      while (optind < argc)
      {
            YENCFILE *y;

            if ((y = yencfile_create(argv[optind++], NULL, YSUPPORT_NOT_SPECIAL, 0)))
            {
                  input_files = (YENCFILE **)xrealloc(input_files, (num_input_files + 1) * sizeof(YENCFILE *));
                  input_files[num_input_files++] = y;
                  total_input_bytes += y->filesize;

                  /* The xxx_construct() functions want this set */
                  y->ok = 1;
            }
      }

      /* Some input files must be specified.. */
      if (!num_input_files)
      {
            Warn(_("no input files"));
            usage(EXIT_FAILURE);
      }
}
/*--- cmdline() ---------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      LOAD_YPOSTRC
      Load the file ~/.ypostrc.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
static void
load_ypostrc(void)
{
      FILE  *fp;
      char  buf[BUFSIZ];
      char  *name, *value;
      char  rcfile[PATH_MAX];
      struct passwd     *pwd;
      int   line = 0;

      if (!(pwd = getpwuid(getuid())) || !pwd->pw_dir)
            return;
      snprintf(rcfile, sizeof(rcfile), "%s/.ypostrc", pwd->pw_dir);
      memset(pwd, 0, sizeof(struct passwd));                            // Get this out of memory
      if (!(fp = fopen(rcfile, "r")))
      {
            if (errno == ENOENT)
                  return;
            ErrERR("%s", rcfile);
      }
      while (fgets(buf, sizeof(buf), fp))
      {
            line++;
            conftrim(buf);
            value = buf;
            name = strsep(&value, "=");
            if (!name || !value)
                  continue;
            strtrim(name);
            strtrim(value);

            /* Remove quotation marks around value if any */
            while ((value[0] == '\'' && value[strlen(value)-1] == '\'')
                         || (value[0] == '"' && value[strlen(value)-1] == '"'))
            {
                  value++;
                  value[strlen(value)-1] = '\0';
            }

#define WARNOVER(OverrideCondition) \
            if (OverrideCondition) \
            { \
                  Warn(_("%s:%d: `%s' option in config file overridden by command-line"), rcfile, line, name); \
                  continue; \
            }

            if (!strcmp(name, "author"))
            {
                  WARNOVER(opt_author || opt_prompt_author);
                  opt_author = xstrdup(value);
            }

            else if (!strcmp(name, "comment"))
            {
                  WARNOVER(opt_comment || opt_prompt_comment);
                  opt_comment = xstrdup(value);
            }

            else if (!strcmp(name, "debug"))
            {
                  WARNOVER(opt_debug);
                  opt_debug = err_debug = opt_verbose = err_verbose = getbool(value);
            }

            else if (!strcmp(name, "force"))
            {
                  WARNOVER(opt_force);
                  opt_force = getbool(value);
            }

            else if ((!strcmp(name, "group") || !strcmp(name, "newsgroup")))
            {
                  WARNOVER(opt_newsgroup);
                  opt_newsgroup = xstrdup(value);
            }

            else if (!strcmp(name, "line"))
            {
                  WARNOVER(opt_line_length != -1);
                  opt_line_length = atoi(value);
            }

            else if (!strcmp(name, "multipart"))
            {
                  WARNOVER(opt_multipart_lines != -1);
                  opt_multipart_lines = atoi(value);
            }

            else if ((!strcmp(name, "messageid") || !strcmp(name, "message-id")))
            {
                  WARNOVER(opt_message_id);
                  opt_message_id = getbool(value);
            }

            else if (!strcmp(name, "nosort"))
            {
                  WARNOVER(opt_nosort);
                  opt_nosort = getbool(value);
            }

            else if (!strcmp(name, "paths"))
            {
                  WARNOVER(opt_keep_paths);
                  opt_keep_paths = getbool(value);
            }

            else if ((!strcmp(name, "pass") || !strcmp(name, "password")))
            {
                  WARNOVER(opt_auth_pass || opt_prompt_pass);
                  opt_auth_pass = xstrdup(value);
            }

            else if (!strcmp(name, "quiet"))
            {
                  WARNOVER(!opt_verbose);
                  opt_debug = opt_verbose = 0;
            }

            else if (!strcmp(name, "retry"))
            {
                  WARNOVER(opt_retry_limit != -1);
                  opt_retry_limit = atoi(value);
            }

            else if (!strcmp(name, "stdout"))
            {
                  WARNOVER(opt_stdout);
                  opt_stdout = getbool(value);
            }

            else if (!strcmp(name, "subject"))
            {
                  WARNOVER(opt_subject || opt_prompt_subject);
                  opt_subject = xstrdup(value);
            }

            else if ((!strcmp(name, "serv") || !strcmp(name, "server")))
            {
                  WARNOVER(opt_nntp_server);
                  opt_nntp_server = xstrdup(value);
            }

            else if (!strcmp(name, "timeout"))
            {
                  WARNOVER(opt_timeout != -1);
                  opt_timeout = atoi(value);
            }

            else if ((!strcmp(name, "user") || !strcmp(name, "username")))
            {
                  WARNOVER(opt_auth_user);
                  opt_auth_user = xstrdup(value);
            }

            else if ((!strcmp(name, "sortfirst") || !strcmp(name, "sort_first")))
            {
                  WARNOVER(opt_sort_first);
                  opt_sort_first = xstrdup(value);
            }

            else if (!strcmp(name, "sfv"))
            {
                  WARNOVER(opt_sfv);
                  opt_sfv = getbool(value);
            }

            else if (!strcmp(name, "crc"))
            {
                  WARNOVER(opt_crc);
                  opt_crc = getbool(value);
            }

            else
                  Warn(_("%s:%d: unknown option `%s' in config file (ignored)"), rcfile, line, name);
      }
      fclose(fp);
}
/*--- load_ypostrc() ----------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      CALCULATE_ENCODED_INFO
      Calculates CRC values, encoded data length, and number of lines for all files matching `type'.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
static void
calculate_encoded_info(ysupportfile_t file_type)
{
      register int ct, x, linect;
      FILE *fp;
      unsigned char buf[BUFSIZ];                                                          /* Input data buffer */
      register size_t rb;                                                                       /* Bytes read this read() */
      register size_t total_bytes_read;                                       /* Total number of bytes read */
      size_t total_bytes;                                                                       /* Total bytes in all files this scan */
      int do_meter = 0;                                                                         /* Display a progress meter? */
      int lines_this_part = 0;                                                            /* Number of lines found for current part */
      register size_t bytes_this_part = 0;                                    /* Number of bytes this part */
      off_t offset;                                                                                   /* Current byte offset in current part */
      YENCPART *part;                                                                           /* Current part info */

      total_bytes_read = total_bytes = (size_t)0;

      /* Get total number of bytes */
      for (ct = 0; ct < num_input_files; ct++)
            if (input_files[ct]->file_type == file_type)
                  total_bytes += input_files[ct]->filesize;
      if (total_bytes > 1000000)
            do_meter = 1;

      /* Scan each file matching `file_type' */
      for (ct = 0; ct < num_input_files; ct++)
      {
            YENCFILE *y = input_files[ct];

            if (y->file_type != file_type)
                  continue;

            y->totalparts = 1;
            lines_this_part = 0;
            bytes_this_part = 0;
            offset = 0;
            linect = 0;
            CRC_START(y->crc);

            /* Initialize our `part' list -- all files have at least one part */
            y->part = (YENCPART **)xrealloc(y->part, (y->totalparts) * sizeof(YENCPART *));
            part = yencpart_create();
            y->part[y->totalparts - 1] = part;
            part->begin = 1;

            if (y->support_data)
            {
                  for (x = 0; x < y->filesize; x++)
                  {
                        CRC_UPDATE(y->crc, y->support_data[x]);

                        /* Update total CRC */
                        CRC_UPDATE(total_crc, y->support_data[x]);

                        if (YSHOULD_ESCAPE(YENCODE(y->support_data[x]),linect,opt_line_length))
                              linect++, y->encsize++;
                        linect++, y->encsize++, offset++, bytes_this_part++;
                        if (linect >= opt_line_length)
                        {
                              y->enclines++, lines_this_part++, linect = 0;

                              /* Add a CR to total_crc to indicate line length */
                              CRC_UPDATE(total_crc, '\r');

                              if (lines_this_part >= opt_multipart_lines)
                              {
                                    y->totalparts++;
                                    part->end = offset;
                                    part->size = bytes_this_part;
                                    y->part = (YENCPART **)xrealloc(y->part, (y->totalparts) * sizeof(YENCPART *));
                                    part = yencpart_create();
                                    y->part[y->totalparts - 1] = part;
                                    part->begin = offset + 1;
                                    lines_this_part = 0;
                                    bytes_this_part = 0;

                                    /* Add a LF to total_crc to indicate file length */
                                    CRC_UPDATE(total_crc, '\n');
                              }
                        }
                  }
            }
            else
            {
                  if (!(fp = fopen(y->input_filename, "r")))
                        ErrERR("%s", y->input_filename);
                  while ((rb = fread(buf, sizeof(unsigned char), sizeof(buf), fp)) > 0)
                  {
                        /* Update CRC and encoded byte count */
                        for (x = 0; x < rb; x++)
                        {
                              CRC_UPDATE(y->crc, buf[x]);

                              /* Update total CRC */
                              CRC_UPDATE(total_crc, buf[x]);

                              if (YSHOULD_ESCAPE(YENCODE(buf[x]),linect,opt_line_length))
                                    linect++, y->encsize++;
                              linect++, y->encsize++, offset++, bytes_this_part++;
                              if (linect >= opt_line_length)
                              {
                                    y->enclines++, lines_this_part++, linect = 0;

                                    /* Add a CR to total_crc to indicate line length */
                                    CRC_UPDATE(total_crc, '\r');

                                    if (lines_this_part >= opt_multipart_lines)
                                    {
                                          y->totalparts++;
                                          part->end = offset;
                                          part->size = bytes_this_part;
                                          y->part = (YENCPART **)xrealloc(y->part, (y->totalparts) * sizeof(YENCPART *));
                                          part = yencpart_create();
                                          y->part[y->totalparts - 1] = part;
                                          part->begin = offset + 1;
                                          part->size = 0;
                                          lines_this_part = 0;
                                          bytes_this_part = 0;

                                          /* Add a LF to total_crc to indicate file length */
                                          CRC_UPDATE(total_crc, '\n');
                                    }
                              }
                        }
                        if (do_meter)
                        {
                              total_bytes_read += rb;
                              meter(total_bytes_read, total_bytes, _("Scanning files"));
                        }
                  }
                  fclose(fp);
            }
            if (linect != 0)
                  y->enclines++;
            part->end = offset;
            part->size = bytes_this_part;

            CRC_FINISH(y->crc);
      }
      if (do_meter)
            meter_clear();
}
/*--- calculate_encoded_info() ------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      CREATE_SUPPORT_FILES
      Precalculates CRC values for all regular input files and generates any requested support files.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
static void
create_support_files(void)
{
      int ct;

      CRC_START(total_crc);

      /* Calculate CRC values, etc. for all regular input files */
      calculate_encoded_info(YSUPPORT_NOT_SPECIAL);

      /* Generate special file data */
      for (ct = 0; ct < num_input_files; ct++)
      {
            YENCFILE *y = input_files[ct];
            switch (y->file_type)
            {
                  case YSUPPORT_IS_SFV:
                        y->support_data = sfv_construct(input_files, num_input_files);
                        y->filesize = strlen(y->support_data);
                        Debug("%s: file generated, %s bytes", y->input_filename, comma(y->filesize));
                        break;

                  case YSUPPORT_IS_CRC:
                        y->support_data = crc_construct(input_files, num_input_files);
                        y->filesize = strlen(y->support_data);
                        Debug("%s: file generated, %s bytes", y->input_filename, comma(y->filesize));
                        break;

                  case YSUPPORT_NOT_SPECIAL:
                  default:
                        break;
            }
      }

      /* Now calculate CRC, etc. for special files */
      calculate_encoded_info(YSUPPORT_IS_SFV);
      calculate_encoded_info(YSUPPORT_IS_CRC);
}
/*--- create_support_files() --------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      OUTPUT_FILE_INFO
      This is called if you pass `--info' on the command line.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
static void
output_file_info(void)
{
      int ct, part;

      for (ct = 0; ct < num_input_files; ct++)
      {
            YENCFILE *y = input_files[ct];

            charline('-');
            printf("     input filename: %s\n", y->input_filename);
            printf("                crc: %08X\n", y->crc);
            printf("          file size: %s\n", comma(y->filesize));
            printf("  encoded data size: %s\n", comma(y->encsize));
            printf("      encoded lines: %s\n", comma(y->enclines));
            printf("        total parts: %s\n", comma(y->totalparts));
            printf("          file type: ");
            switch (y->file_type)
            {
                  case YSUPPORT_IS_SFV: printf("support file - .sfv\n"); break;
                  case YSUPPORT_IS_CRC: printf("support file - .crc\n"); break;
                  case YSUPPORT_NOT_SPECIAL: default: printf("regular file\n"); break;
            }
            printf("       support data: %s\n", y->support_data ? "yes" : "no");
            for (part = 0; part < y->totalparts; part++)
                  printf("           part %03d: begin=%lu end=%lu size=%u\n", part + 1, y->part[part]->begin,
                               y->part[part]->end, y->part[part]->size);
      }
      charline('-');
      exit(EXIT_SUCCESS);
}
/*--- output_file_info() ------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      POST_FILE
      Posts a single part file to the news server.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
static void
post_file(YENCFILE *y)
{
      unsigned char *subject = NULL, *headers = NULL;       /* Subject and headers, current part */
      FILE *fp = NULL;                                                                    /* Input file (if reading from a file) */
      unsigned char inbuf[BUFSIZ], outbuf[BUFSIZ];                /* Input and output buffers */
      register unsigned char c;                                                     /* Current character being encoded */
      register int ct, linect, lines, total_lines;
      register size_t written;                                                      /* Bytes written this part */
      size_t rb;                                                                                /* Number of bytes read */
      unsigned char *reply = NULL;                                            /* Reply from server */
      register off_t offset;                                                        /* Current offset into entire buffer/file */
      int orig_debug = opt_debug;                                             /* Original debug value (hide encdata) */
      register crc32_t pcrc;                                                        /* CRC for this part (if multipart) */
      int   replynum = 0;                                                                 /* Numeric value of server reply */
      off_t start_offset;                                                                 /* Starting offset for this part (for retrying) */
      int   retry = 0;                                                                    /* Current retry number */
      float elapsed;                                                                            /* Elapsed time for this part */
      char  desc[80];                                                                     /* Description of current action */

      opt_debug = err_debug = 0;

      /* Open the input file (if there is one) */
      if (!y->support_data && !(fp = fopen(y->input_filename, "r")))
            ErrERR("%s", y->input_filename);

      /*
      **  Loop through each part of this file
      */
      for (offset = 0, part_current = 1; part_current <= y->totalparts; )
      {
            /*
            **  If we are resuming, we might need to skip this file.
            **  We do not want to start posting until total_posted >= opt_resume_msg.
            */
            if (opt_resume_msg && (total_posted+1 < opt_resume_msg))
            {
                  offset += y->part[part_current-1]->size;
                  subject = usenet_make_subject(y, part_current);
                  Verbose("%s", subject);
                  free(subject);
                  Verbose("* Message skipped (resuming, already posted)");
                  Verbose(" ");
                  retry = 0;
                  part_current++;
                  total_posted++;
                  continue;
            }

            /*
            **  Initialize data; generate subject and headers; send NNTP POST command and headers
            */
            start_offset = offset;
            subject = usenet_make_subject(y, part_current);
            headers = usenet_make_headers(y, part_current);
            if (retry)
                  snprintf(desc, sizeof(desc), "%s %d of %d", _("Retry"), retry, opt_retry_limit);
            else
            {
                  snprintf(desc, sizeof(desc), "%s of %s", comma1(total_posted+1), comma2(total_messages));
                  Verbose("%s", subject);
            }
            if (!opt_stdout)
                  nntptransx("POST\n");                                             /* Send NNTP POST */
            sock_write(headers, strlen(headers));                       /* Output headers */
            free(subject);
            free(headers);

            /*
            **  Write the yEnc "=ybegin" line
            */
            if (y->totalparts == 1)
                  sock_printf("=ybegin line=%d size=%u name=%s\n",
                                          opt_line_length, y->filesize, STRIP_PATH(y->input_filename));
            else
                  sock_printf("=ybegin part=%d total=%d line=%d size=%u name=%s\n",
                                          part_current, y->totalparts, opt_line_length, y->filesize, STRIP_PATH(y->input_filename));

            /*
            **  Determine the total number of lines for the current part
            */
            if (y->totalparts == 1)
                  total_lines = y->enclines;
            else
                  total_lines = (part_current < y->totalparts) ? opt_multipart_lines : (y->enclines % opt_multipart_lines);
            linect = lines = 0;

            /*
            **  Write the yEnc "=ypart" line (if this is a multipart archive)
            */
            if (y->totalparts > 1)
                  sock_printf("=ypart begin=%lu end=%lu\n", y->part[part_current-1]->begin, y->part[part_current-1]->end);

            /*
            **  Output encoded data for this part
            */
            CRC_START(pcrc);
            written = 0;
            timer_reset(NULL);
            if (y->support_data)
            {
            for (ct = offset; ct < y->filesize && lines < opt_multipart_lines; ct++)
                  {
                        offset++;
                        CRC_UPDATE(pcrc, y->support_data[ct]);
                        c = YENCODE(y->support_data[ct]);

               if (YSHOULD_ESCAPE(c,linect,opt_line_length))
                        {
                              outbuf[linect++] = '=';
                              c = YESCAPE(c);
                        }
                        outbuf[linect++] = c;
                        if (linect >= opt_line_length)
                        {
                              outbuf[linect++] = '\0';
                              if (!opt_stdout || (opt_stdout && !isatty(STDOUT_FILENO)))
                                    written += sock_puts_meter(outbuf, written, y->part[part_current-1]->size, desc);
                              linect = 0;
                              lines++;
                        }
                  }
            }
            else        /* Reading from a file */
            {
                  fseek(fp, offset, SEEK_SET);
                  while ((lines < opt_multipart_lines) && ((rb = fread(inbuf, sizeof(unsigned char), sizeof(inbuf), fp)) > 0))
                  {
                        for (ct = 0; ct < rb && lines < opt_multipart_lines; ct++)
                        {
                              offset++;
                              CRC_UPDATE(pcrc, inbuf[ct]);
                              c = YENCODE(inbuf[ct]);

                              if (YSHOULD_ESCAPE(c,linect,opt_line_length))
                              {
                                    outbuf[linect++] = '=';
                                    c = YESCAPE(c);
                              }
                              outbuf[linect++] = c;
                              if (linect >= opt_line_length)
                              {
                                    outbuf[linect++] = '\0';
                                    if (!opt_stdout || (opt_stdout && !isatty(STDOUT_FILENO)))
                                          written += sock_puts_meter(outbuf, written, y->part[part_current-1]->size, desc);
                                    linect = 0;
                                    lines++;
                              }
                        }
                  }
            }

            /*
            **  Finished with this part - close the current line if we've output any data
            */
            if (linect)
            {
                  outbuf[linect++] = '\0';
                  if (!opt_stdout || (opt_stdout && !isatty(STDOUT_FILENO)))
                        sock_puts(outbuf);
            }
            CRC_FINISH(pcrc);
            elapsed = timer_elapsed(NULL);

            /*
            **  If output is going to stdout and stdout is a terminal, we didn't output any of the
            **  encoded data (to remain screen-friendly).  Output a short message explaining this.
            */
            if (opt_stdout && isatty(STDOUT_FILENO))
            {
                  puts(_("<< ENCODED DATA OMITTED SINCE OUTPUT IS TO A TERMINAL >>"));
                  puts(_("<< TO ENABLE ENCODED DATA,  REDIRECT STDOUT TO A FILE >>"));
            }

            /*
            **  Write the yEnc "=yend" line
            */
            if (y->totalparts == 1)
                  sock_printf("=yend size=%u crc32=%08X\n", y->filesize, y->crc);
            else
            {
                  if (part_current == y->totalparts)
                        sock_printf("=yend size=%u part=%d pcrc32=%08X crc32=%08X\n", y->part[part_current-1]->size, part_current, pcrc, y->crc);
                  else
                        sock_printf("=yend size=%u part=%d pcrc32=%08X\n", y->part[part_current-1]->size, part_current, pcrc);
            }

            /*
            **  Finish the NNTP POST command and check the server's result
            */
            if (!opt_stdout)
                  meter_clear();
            sock_puts(".");         /* Do this even if opt_stdout, as a separator there */
            if (!opt_stdout)
            {
                  if (!(reply = sock_gets()))
                        Err(_("server did not reply to our command"));
                  replynum = nntp_get_reply_num(reply);
                  if (STATUS_ERR(replynum))
                        Verbose("* %s", strtrim(reply));
                  else
                        Verbose("* %s (%.2fk/s)", strtrim(reply),
                                      (float)((float)((float)y->part[part_current-1]->size / 1024.0) / elapsed));

                  // Sleep for a couple of seconds, so that we make sure our files are posted in order
                  sleep(2);
            }
            else
                  Verbose("* Done");

            /*
            **  If this part was posted successfully, move on to the next part
            */
            if (opt_stdout || !STATUS_ERR(replynum))
            {
                  Verbose(" ");
                  retry = 0;
                  part_current++;
                  total_posted++;
            }
      else        /* An error occurred - incremement retry count, reconnect, and retry */
            {
                  offset = start_offset;
                  retry++;
                  if (retry > opt_retry_limit)
                        Err(_("posting failed; retry limit reached"));

                  /* Disconnect from server and reconnect */
                  nntp_disconnect();
                  sleep(1);
                  nntp_connect();
            }
   }

      /* Close the input file (if there was one) */
      if (!y->support_data)
            fclose(fp);
      opt_debug = err_debug = orig_debug;
}
/*--- post_file() -------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      FINISH_TOTAL_CRC
      Completes the calculation of the `total_crc' global variable, which is a checksum that may
      be optionally used when resuming a post.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
static void
finish_total_crc(void)
{
      register unsigned char *c, *subject;
      YENCFILE *y;

      /* Finish total_crc by calculating subject lines for each message, and adding their crc to the end */
      for (file_current = 1; file_current <= num_input_files; file_current++)
      {
            y = input_files[file_current-1];
            for (part_current = 1, part_total = y->totalparts; part_current <= part_total; part_current++)
            {
                  subject = usenet_make_subject(y, part_current);
                  for (c = subject; *c; c++)
                        CRC_UPDATE(total_crc, *c);
                  free(subject);
            }
      }
      CRC_FINISH(total_crc);

      if (opt_resume_crc && (opt_resume_crc != total_crc))
            Err(_("resume checksum (%08X) does not match posting checksum (%08X)"), opt_resume_crc, total_crc);
}
/*--- finish_total_crc() ------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      CLEANUP
      If the posting has begun, this will let the user know how they can restart the post.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
void
cleanup(int code)
{
      int ct, special;

      if (!posting_started || !total_posted)
            exit(EXIT_FAILURE);

      for (ct = special = 0; ct < num_input_files && !special; ct++)
            if (input_files[ct]->file_type != YSUPPORT_NOT_SPECIAL)
                  special++;

      fputs((isatty(STDERR_FILENO)) ? "\a\n\n" : "\n\n", stderr);

      fprintf(stderr, "%s\n\n", _("NOTICE: The program ended while messages were being posted!"));

      fprintf(stderr, _("To resume the post that was just interrupted, run %s\n"), short_progname);
      fprintf(stderr, _("again with the same arguments as before, plus the following:\n\n"));

      /* We can't list the total_crc if there were special files present, since some of them
            (like .sfv) contain data that will change on each run (the date/time), thus changing
            the crc */
      if (special)
            fprintf(stderr, "\t--resume=%d\n\n", total_posted+1);
      else
            fprintf(stderr, "\t--resume=%d,%08X\n\n", total_posted+1, total_crc);

      exit(EXIT_FAILURE);
}
/*--- cleanup() ---------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      ADD_SUPPORT_FILE
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
static void
add_support_file(const char *filename, const char *ext, ysupportfile_t type)
{
      char  *fn;                                                                          /* Filename to use */
      char  *def = NULL;
      char  namebuf[PATH_MAX];
      int   ct;
      char  *c;
      YENCFILE *y;                                                                        /* New file */

      /* If no filename was specified, try to find a .nfo or .m3u file and take the name from that */
      if (!filename)
            for (ct = 0; ct < num_input_files; ct++)
                  if ((c = strrchr(input_files[ct]->input_filename, '.')))
                        if (!strcasecmp(c, ".m3u") || !strcasecmp(c, ".nfo"))
                        {
                              if ((c = strrchr(input_files[ct]->input_filename, '/')))
                                    strncpy(namebuf, c+1, sizeof(namebuf)-1);
                              else
                                    strncpy(namebuf, input_files[ct]->input_filename, sizeof(namebuf)-1);
                              if ((c = strrchr(namebuf, '.')))
                                    *c = '\0';
                              def = namebuf;
                        }
      fn = yencfile_default_filename(filename, def ? def : input_files[0]->input_filename, ext);
      if ((y = yencfile_create(fn, NULL, type, 0)))
      {
            input_files = (YENCFILE **)xrealloc(input_files, (num_input_files + 1) * sizeof(YENCFILE *));
            input_files[num_input_files++] = y;
      }
}
/*--- add_support_file() ------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      MAIN
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
int
main(int argc, char **argv)
{
      register int ct;

      set_progname(argv[0]);
      err_set_exit(cleanup);

      signal(SIGWINCH, set_screen_width);
      signal(SIGHUP, cleanup);
      signal(SIGINT, cleanup);
      signal(SIGQUIT, cleanup);
      signal(SIGABRT, cleanup);
      signal(SIGTERM, cleanup);

      setlocale(LC_ALL, "");
      bindtextdomain(PACKAGE, LOCALEDIR);
      textdomain(PACKAGE);
      cmdline(argc, argv);
      load_ypostrc();

      /* Set default options if values were not specified */
      if (opt_timeout == -1)
            opt_timeout = DEFAULT_SOCK_TIMEOUT;
      if (opt_line_length == -1)
            opt_line_length = Y_LL;
      if (opt_multipart_lines == -1)
            opt_multipart_lines = DEFAULT_MULTIPART_LINES;
      if (opt_retry_limit == -1)
            opt_retry_limit = DEFAULT_RETRY_LIMIT;
      opt_multipart_lines -= 3;                                                     /* Subtract 3 lines for the =y lines */

      /* Add support files if requested */
      if (opt_sfv) add_support_file(opt_sfv_filename, ".sfv", YSUPPORT_IS_SFV);
      if (opt_crc) add_support_file(opt_crc_filename, ".crc", YSUPPORT_IS_CRC);

      /* Sort the input file list */
      if (!opt_nosort)
      {
            yencfile_seed_sort_first_extensions(opt_sort_first);
            qsort(input_files, num_input_files, sizeof(YENCFILE *), yencfile_cmp);
      }

      create_support_files();                                                       /* Create support files if requested */
      if (opt_info)
            output_file_info();

      /* Set total number of parts and files */
      part_total = file_total = total_messages = total_posted = 0;
      for (ct = 0; ct < num_input_files; ct++)
      {
            part_total += input_files[ct]->totalparts;
            file_total++;
            total_messages += input_files[ct]->totalparts;
      }
      prompt_for_missing();                                                   /* Prompt user for any missing information */

      finish_total_crc();                                                           /* Finish calculating total CRC */

      if (!opt_force && !opt_stdout)
            prompt_confirm_post();                                            /* Confirm posting */

      /* Post all files */
      nntp_connect();
      posting_started = 1;
      for (ct = 0; ct < num_input_files; ct++, file_current++)
      {
            part_total = input_files[ct]->totalparts;
            post_file(input_files[ct]);
      }
      posting_started = 0;

      return (EXIT_SUCCESS);
}
/*--- main() ------------------------------------------------------------------------------------*/

/* vi:set ts=3: */

Generated by  Doxygen 1.6.0   Back to index