Logo Search packages:      
Sourcecode: yencode version File versions

usenet.c

/**************************************************************************************************
      $Header: /pub/cvsroot/yencode/src/ypost/usenet.c,v 1.1 2002/03/15 15:10:49 bboy Exp $
      Routines used by `ypost' to validate and construct Usenet (RFC 1036) data.

      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"


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      VALIDATE_EMAIL
      Is this a valid email address?
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
static char *
validate_email(char *email)
{
      /* XXX: This is VERY non-robust */
      if (strchr(email, '@'))
            return (NULL);
      else
            return (_("invalid email address"));
}
/*--- validate_email() --------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      USENET_VALID_FROM
      Checks the supplied address to make sure it's a conformant From: value.  Will make minor
      adjustments to the string if possible.  Returns NULL if conformant, or a string describing
      the problem if not.  This function is not that strict.

      RFC 1036 gives the following examples as valid addresses:

            From: mark@cbosgd.ATT.COM
            From: mark@cbosgd.ATT.COM (Mark Horton)
            From: Mark Horton <mark@cbosgd.ATT.COM>
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
char *
usenet_valid_From(char *from, size_t len)
{
      char  *paren, *angle, *email, *comment, *reason;
      char  fromcopy[BUFSIZ];

      strtrim(from);
      strncpy(fromcopy, from, sizeof(fromcopy)-1);
      paren = strchr(fromcopy, '(');
      angle = strchr(fromcopy, '<');

      // First form: No parens, no angle brackets
      if (!paren && !angle)
      {
            email = fromcopy;
            opt_sender = xstrdup(email);
            strtrim(opt_sender);
            return (validate_email(email));
      }

      // Second form: Comment in parentheses
      if (paren)
      {
            email = fromcopy;
            comment = paren;
            *(comment++) = '\0';
            if (!(paren = strchr(comment, ')')))
                  return (_("unterminated comment in author name"));
            *paren = '\0';
            opt_sender = xstrdup(email);
            strtrim(opt_sender);
            if ((reason = validate_email(email)))
                  return (reason);
            return (NULL);
      }

      // Third form: Email in angle brackets
      if (angle)
      {
            comment = fromcopy;
            email = angle;
            *(email++) = '\0';
            if (!(angle = strchr(email, '>')))
                  return (_("unterminated email address in author name"));
            *angle = '\0';
            opt_sender = xstrdup(email);
            strtrim(opt_sender);
            if ((reason = validate_email(email)))
                  return (reason);
            return (NULL);
      }
      return (_("unknown or invalid format for author (see ypost(1))"));
}
/*--- usenet_valid_From() -----------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      USENET_VALID_SUBJECT
      Checks the supplied subject data to make sure it's a conformant Subject: value.
      Returns NULL if conformant, or a string describing the problem if not.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
char *
usenet_valid_Subject(char *str, size_t len)
{
      strtrim(str);
      /* XXX: This isn't much of a check! */
      return (NULL);
}
/*--- usenet_valid_Subject() --------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      USENET_DATE
      Returns a static string containing the date in the format specified by RFC 822 / RFC 1036
      Ex: Wdy, DD Mon YY HH:MM:SS TIMEZONE
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
char *
usenet_date(void)
{
      static char datebuf[80];                                                      /* Return value */
      time_t now;                                                                               /* Current time */
      const struct tm *tm;                                                                /* Broken down time */

      time(&now);
      tm = gmtime(&now);
      strftime(datebuf, sizeof(datebuf)-1, "%a, %d %b %Y %H:%M:%S %Z", tm);
      return (datebuf);
}
/*--- usenet_date() -----------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      USENET_MESSAGE_ID
      Returns an unique message ID.  The basic format is:
            <time><pid><idcount>@<hostname>
      The <pid> ensures that two copies of ypost running simultaneously will not use the same
      Message-ID if they post in the same second, and the <idcount> ensures that if this instance
      of ypost posts many messages in the same second they will still be unique, as it increments
      with each Message-ID generated.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
char *
usenet_message_id(void)
{
      struct utsname uts;
      static int idcount = 0;                                                       /* Number of IDs generated so far */
      static char id[1024];                                                         /* The ID generated */

      if (uname(&uts))
            ErrERR(_("unable to determine hostname"));
      snprintf(id, sizeof(id), "<%lx%x%x@%s>", time(NULL), getpid(), idcount++, uts.nodename);
      return (id);
}
/*--- usenet_message_id() -----------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      PAD_NUMBER
      Returns a pointer to a static string containing a number formatted to the width of the 
      `total' number.  0 indicates 'x' if use_x is nonzero.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
char *
pad_number(int number_to_pad, int total, int use_x)
{
      int width = numeric_width(total);
      static char numbuf[16];

      if (number_to_pad <= 0 && use_x)
            snprintf(numbuf, sizeof(numbuf), "%*.*s", width, width, "xxxxxxxxxxxxxxxxx");
      else
            snprintf(numbuf, sizeof(numbuf), "%0*d", width, number_to_pad);
      return (numbuf);
}
/*--- pad_number() ------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      FORMAT_SUBJECT
      Replaces variables with values in the subject string specified.  The string assumed to be
      dynamically allocated, and will be realloc()'d to accomodate the new string.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
static void
format_subject(char *subject)
{
      char *c;
      char result[BUFSIZ], *r;
      int  len = 0;

      memset(result, 0, sizeof(result));
      for (c = subject, r = result; *c && len < sizeof(result)-1; c++)
      {
            if (*c == '%')
                  switch (*(c+1))
                  {
                        case 'p':         /* $p: Current part number */
                              len += snprintf(r, sizeof(result) - strlen(result), "%s", pad_number(part_current, part_total, 1));
                              r = result + len, c++;
                              break;
                        case 'P':         /* $P: Total number of parts */
                              len += snprintf(r, sizeof(result) - strlen(result), "%d", part_total);
                              r = result + len, c++;
                              break;
                        case 'f':         /* $f: Current file number */
                              len += snprintf(r, sizeof(result) - strlen(result), "%s", pad_number(file_current, file_total, 0));
                              r = result + len, c++;
                              break;
                        case 'F':         /* $F: Total number of files */
                              len += snprintf(r, sizeof(result) - strlen(result), "%d", file_total);
                              r = result + len, c++;
                              break;
                        default:
                              result[len++] = *c;
                              break;
                  }
            else
                  *(r++) = *c, len++;
      }
      subject = realloc(subject, len);
      subject[len] = '\0';
      memcpy(subject, result, len);
}
/*--- format_subject() --------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      USENET_MAKE_SUBJECT
      Constructs the subject line for the current file.  `part' is the current part number (relevant
      only if the file is multipart).  If `part' is -1, "XX" will be inserted for the confirmation
      output.

      Suggested format, single part binary:

            [Comment1] "filename" 12345 yEnc bytes [Comment2]

      [Comment1] and [Comment2] are optional. The filename should always be enclosed in quotes;
      this allows for easy detection, even when the filename includes spaces or other special
      characters. The word "yEnc" should be placed in between the file size and the word "bytes".


      Suggested format, multipart binary:

            [Comment1] "filename" yEnc (partnum/numparts) [size] [Comment2]

      Again, [Comment1] and [Comment2] are optional. The [size] value is also optional here.
      The filename must be included, in quotes. The keyword "yEnc" is mandatory, and must
      appear between the filename and the size (or Comment2, if size is omitted). Future
      revisions of the draft may specify additional information may be inserted between the
      "yEnc" keyword and the opening parenthesis of the part number. 
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
unsigned char *
usenet_make_subject(YENCFILE *y, int part)
{
      unsigned char *subj = NULL;

      if (opt_subject)
            sdprintf(&subj, "[%s] ", opt_subject);
      sdprintf(&subj, "\"%s\" ", STRIP_PATH(y->input_filename));

      if (y->totalparts < 2)                                                        /* Single part subject */
            sdprintf(&subj, "%u yEnc bytes", y->filesize);
      else                                                                                            /* Multi part subject */
      {
            /* Get part number as a string */
            sdprintf(&subj, "yEnc (%s/%d) %u bytes", pad_number(part, y->totalparts, 1), y->totalparts, y->filesize);
      }
      if (opt_comment)
            sdprintf(&subj, " [%s]", opt_comment);
      format_subject(subj);

      return (subj);
}
/*--- usenet_make_subject() ---------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      USENET_MAKE_HEADERS
      Creates the full set of headers for a single message.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
unsigned char *
usenet_make_headers(YENCFILE *y, int part)
{
      unsigned char *hdr = NULL, **h = &hdr;                            /* The header data */
      unsigned char *subject = usenet_make_subject(y, part);

      sdprintf(h, "From: %s" CRLF, opt_author);
      if (opt_sender)
            sdprintf(h, "Sender: %s" CRLF, opt_sender);
      sdprintf(h, "User-Agent: %s/" VERSION " (http://www.yencode.org/)" CRLF, short_progname);
      sdprintf(h, "Date: %s" CRLF, usenet_date());
      sdprintf(h, "Newsgroups: %s" CRLF, opt_newsgroup);
      sdprintf(h, "Subject: %s" CRLF, subject);

      if (opt_message_id)
            sdprintf(h, "Message-ID: %s" CRLF, usenet_message_id());

      /* Calculate number of lines in this post */
      if (y->totalparts == 1)
            sdprintf(h, "Lines: %u" CRLF, y->enclines + 2);
      else
      {
            if (part < y->totalparts)
                  sdprintf(h, "Lines: %u" CRLF, opt_multipart_lines + 3);
            else
                  sdprintf(h, "Lines: %u" CRLF, (y->enclines % opt_multipart_lines) + 3);
      }
      sdprintf(h, CRLF);

      free(subject);
      return (hdr);
}
/*--- usenet_make_headers() ---------------------------------------------------------------------*/

/* vi:set ts=3: */

Generated by  Doxygen 1.6.0   Back to index