ftp.nice.ch/pub/next/unix/network/news/slrn0.9.0.0.s.tar.gz#/slrn/src/post.c

This is post.c in view mode; [Download] [Up]

/*  Copyright (c) 1995 John E. Davis (davis@space.mit.edu)
 *  All rights reserved.
 */
/* post an article */
#include "config.h"
#include "features.h"

#include <stdio.h>
#include <string.h>


#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif

#ifdef HAVE_STDLIB_H
# include <stdlib.h>
#endif

#include <sys/types.h>
#include <time.h>
#include <slang.h>
#include "jdmacros.h"


/* #include "clientlib.h" */
#include "slrn.h"
#include "server.h"
#include "misc.h"
#include "post.h"
#include "group.h"
#include "art.h"
#include "uudecode.h"

#if SLRN_HAS_MIME
# include "mime.h"
#endif

char *Slrn_Courtesy_CC_Message = NULL;
char *Slrn_Save_Posts_File;
char *Slrn_Last_Message_Id;
char *Slrn_Custom_Headers;

#ifdef VMS
# define SYSTEM_OS_NAME		"VMS"
#else
# ifdef __os2__
#  define SYSTEM_OS_NAME	"OS2"
# else
#  ifdef unix
#   define SYSTEM_OS_NAME       "UNIX"
#  else
#   define SYSTEM_OS_NAME	"UNKNOWN"
#  endif
# endif
#endif


#define SLRN_GEN_MSGID
#ifdef SLRN_GEN_MSGID
static char *slrn_create_message_id (void)
{
   unsigned long pid, now;
   static unsigned char baseid[64];
   unsigned char *b, *t, tmp[32];
   char *chars32 = "0123456789abcdefghijklmnopqrstuv";
   static unsigned long last_now;
   
   while (1)
     {
	if ((Slrn_User_Info.posting_host == NULL)
	    || ((time_t) -1 == time ((time_t *)&now)))
	  return NULL;
	
	if (now != last_now) break;
	sleep (1);
     }
   last_now = now;
   
   pid = (unsigned long) getpid ();
   now -= 0x28000000;
   
   b = baseid;
   t = tmp;
   while (now)
     {
	*t++ = chars32[now & 0x1F];
	now = now >> 5;
     }
   while (t > tmp)
     {
	t--;
	*b++ = *t;
     }
   *b++ = '.';
   
   t = tmp;
   while (pid)
     {
	*t++ = chars32[pid & 0x1F];
	pid = pid >> 5;
     }
   while (t > tmp)
     {
	t--;
	*b++ = *t;
     }
   
   *b++ = '.';
   t = (unsigned char *) Slrn_User_Info.username;
   if (t != NULL)
     while ((*t != 0) && (b < baseid + sizeof(baseid) - 1)) *b++ = *t++;
   *b = 0;
   
   return (char *) baseid;
}
#endif
void slrn_add_signature (FILE *fp)
{
   FILE *sfp;
   char buf[256];
   
   if ((sfp = slrn_open_home_file (Slrn_User_Info.signature, "r", buf, 0)) != NULL)
     {
	/* Apparantly some RFC suggests the -- \n. */
        fprintf(fp, "\n\n-- \n");
        while (fgets (buf, sizeof(buf) - 1, sfp) != NULL)
	  {
	     fprintf(fp, "%s", buf);
	  }
        slrn_fclose(sfp);
     }
}

static int is_empty_header (char *line)
{
   char *b;
   
   if ((*line == ' ') || (*line == '\t')) return 0;
   
   b = slrn_strchr (line, ':');
   if (b == NULL) return 0;
   
   b = slrn_skip_whitespace (b + 1);
   return (*b == 0);
}


static int slrn_cc_file (char *file, char *to)
{
#if defined(VMS) || !SLRN_HAS_PIPING
   return -1;
#else
   FILE *pp, *fp;
   char line[1024];
   unsigned char *b;
   unsigned int cc_line = 0;
   unsigned int linenum;
   int num_ccd;
   
   if (NULL == (fp = fopen (file, "r")))
     {
	slrn_error ("Unable to open %s.");
	return -1;
     }
   
   /* Look for CC line */
   linenum = 0;
   while ((NULL != fgets (line, sizeof (line) - 1, fp)) && (*line != '\n'))
     {
	linenum++;
	if (0 == slrn_case_strncmp ((unsigned char *)line,
				    (unsigned char *) "Cc: ", 4))
	  {
	     b = (unsigned char *) slrn_skip_whitespace (line + 4);
	     if (*b && (*b != ',')) cc_line = linenum;
	     break;
	  }
     }
   
   /* At this point, if all has gone well line contains the cc information */
   
   if (cc_line == 0)
     {
	slrn_fclose (fp);
	return -1;
     }
   
   pp = slrn_popen (Slrn_SendMail_Command, "w");
   if (pp == NULL)
     {
	slrn_fclose (fp);
	return -1;
     }
   
   fputs ("To: ", pp);
   num_ccd = 0;
   b = (unsigned char *) line + 4;
   while (*b != 0)
     {
	unsigned char *bmin, ch;
	/* skip to first non-whitespace, non-comma char */
        if ((*b <= ' ') || (*b == ','))
	  {
	     b++;
	     continue;
	  }
	
	bmin = b;
	/* Now skip past to white space or comma */
	while (((ch = *b) != ',') && (ch > ' ')) b++;
	
	if ((b == bmin + 6)
	    && (0 == slrn_case_strncmp (bmin, (unsigned char *) "poster", 6)))
	  {
	     if (to != NULL)
	       {
		  if (num_ccd) putc (',', pp);
		  fputs (to, pp);
		  num_ccd++;
		  to = NULL;
	       }
	  }
	else
	  {
	     if (num_ccd) putc (',', pp);
	     fwrite ((char *)bmin, 1, (unsigned int) (b - bmin), pp);
	     num_ccd++;
	  }
     }
   putc ('\n', pp);
   
   rewind (fp);
   linenum = 0;
   
   while ((NULL != fgets (line, sizeof (line) - 1, fp)) && (*line != '\n'))
     {
	linenum++;
	if (linenum == cc_line) continue;
	if (is_empty_header (line)) continue;
	if (0 == slrn_case_strncmp ((unsigned char *)line,
				    (unsigned char *) "To: ", 4))
	  continue;
	
	/* There is some discussion of this extension to mail headers.  For
	 * now, assume that this extension will be adopted.
	 */
	if (0 == slrn_case_strncmp ((unsigned char *)line,
				    (unsigned char *) "Newsgroups: ", 12))
	  {
	     fputs ("Posted-To: ", pp);
	     fputs (line + 12, pp);
	  }
	else
	  fputs (line, pp);
     }
   
# if SLRN_HAS_MIME
   if (Slrn_Use_Mime) slrn_mime_add_headers (pp);
# endif
   
   fputs ("\n", pp);
   
   if ((NULL != Slrn_Courtesy_CC_Message) && (*Slrn_Courtesy_CC_Message))
     fprintf (pp, "%s\n", Slrn_Courtesy_CC_Message);
   
# if SLRN_HAS_MIME
   if (Slrn_Use_Mime) fp = slrn_mime_encode (fp);
# endif
   
   while (NULL != fgets (line, sizeof (line) - 1, fp))
     {
	fputs (line, pp);
     }
   slrn_fclose (fp);
   slrn_pclose (pp);
   return 0;
#endif
}

/* This function needs work-- in fact, I ought to move this to a separate
 * file for this purpose.
 */
static int check_file_for_posting (char *file)
{
   char line[1024], *the_line;
   FILE *fp;
   unsigned int num;
   char *err;
   int rsp;
   int newsgroups_found, subject_found;
   char ch;
   char *colon;
   
   try_again:
   newsgroups_found = subject_found = 0;
   err = NULL;
   fp = fopen (file, "r");
   
   if (fp == NULL)
     {
	slrn_error ("Unable to open %s", file);
	return -1;
     }
   
   the_line = line;
   
   /* scan the header */
   num = 0;
   while (NULL != fgets (line, sizeof (line), fp))
     {
	ch = *line;	
	num++;
	if ((ch == ' ') || (ch == '\t') || (ch == '\n'))
	  {
	     if (num == 1) 
	       {
		  err = "The first line must begin with a header.";
		  break;
	       }
	     if (ch == '\n') break;
	     
	     continue;
	  }
	
	if (NULL == (colon = slrn_strchr (line, ':')))
	  {
	     err = "Expecting a header.  This is not a header line.";
	     break;
	  }
	
	if (!slrn_case_strncmp ((unsigned char *) line, (unsigned char *) "Subject:", 8))
	  {
	     if (is_empty_header (line))
	       {
		  err = "The subject header is not allowed be to empty.";
		  break;
	       }
	     subject_found = 1;
	     continue;
	  }
	
	if (!slrn_case_strncmp ((unsigned char *) line, (unsigned char *) "Newsgroups:", 11))
	  {
	     if (is_empty_header (line)) 
	       {
		  err = "The Newsgroups header is not allowed be to empty.";
		  break;
	       }
	     newsgroups_found = 1;
	     continue;
	  }
	
	/* slrn will remove it later if it is empty */
	if (is_empty_header (line)) continue;
	
	if (*(colon + 1) != ' ') 
	  {
	     err = "A space must follow the ':' in a header";
	     break;
	  }
	
	if (!slrn_case_strncmp ((unsigned char *) line, (unsigned char *) "From:", 5))
	  {
	     err = "This news reader will not accept user generated From lines.";
	     break;
	  }
     }

   if (err == NULL) 
     {
	if (subject_found == 0) 
	  {
	     err = "Subject header is required.";
	     num = 0;
	  }
	else if (newsgroups_found == 0)
	  {
	     err = "Newsgroups header is required.";
	     num = 0;
	  }
     }
   
   /* Now body.  Check for non-quoted lines. */
   if (err == NULL) 
     {
	unsigned int qlen = strlen (Slrn_Quote_String);
	
	err = "Your message does not appear to have any unquoted text.";
	while (NULL != fgets (line, sizeof (line), fp))
	  {
	     num++;
	     if (!strncmp (line, Slrn_Quote_String, qlen))
	       continue;
	     
	     colon = slrn_skip_whitespace (line);
	     if (*colon == 0) continue;
	     
	     err = NULL;
	     break;
	  }
	the_line = NULL;
     }
   
   fclose (fp);

   if (err == NULL) return 0;

   Slrn_Full_Screen_Update = 1;

   slrn_set_color (0);
   
   SLsmg_cls ();
   SLsmg_gotorc (2,0);
   slrn_set_color (SUBJECT_COLOR);
   SLsmg_write_string ("Your message is not acceptable for the following reason:");
   slrn_set_color (ERROR_COLOR);
   SLsmg_gotorc (4,8); SLsmg_write_string (err);
   if (num && (the_line != NULL))
     {
	SLsmg_gotorc (6,0);
	slrn_set_color (SUBJECT_COLOR);
	SLsmg_printf ("This message was generated while looking at line %d:", num);
	SLsmg_gotorc (8,0);
	slrn_set_color (QUOTE_COLOR);
	SLsmg_printf (the_line);
	SLsmg_gotorc (12, 0);
	slrn_set_color (ARTICLE_COLOR);
	SLsmg_write_string ("Perhaps this error was generated because you did not separate the header");
	SLsmg_gotorc (13, 0);
	SLsmg_write_string ("section from the body by a BLANK line.");
     }
   
   rsp = slrn_get_response ("yYnNcC\007", "Press 'Y' to re-edit or 'C' to cancel");
   rsp |= 0x20;
   if (rsp == 'y')
     {
	if (slrn_edit_file (file, num) < 0) return -1;
	goto try_again;
     }
   return -1;
}

int slrn_post_file (char *file, char *to)
{
   char line[1024], *linep;
   int len, header;
   FILE *fp;
   int rsp;
   int perform_cc;
#ifdef SLRN_GEN_MSGID
   char *msgid;
   int has_messageid = 0;
#endif
   
   try_again:
   perform_cc = 0;
   while (1)
     {
	rsp = slrn_get_response ("yYnNeE", "Post the message? Y-es, N-o, E-dit");
	rsp |= 0x20;
	if (rsp == 'n') return -1;
	if (rsp == 'y') break;
	if (slrn_edit_file (file, 1) < 0) 
	  {
	     slrn_error ("User abort.");
	     return -1;
	  }
     }
   
   if (-1 == check_file_for_posting (file)) return -1;
   
   slrn_message ("Posting...");  slrn_smg_refresh ();
   
   if ((Slrn_Save_Posts_File != NULL) && (*Slrn_Save_Posts_File))
     {
	FILE *infp, *outfp;
	time_t now;
	char save_post_file[256];
	
	if (NULL == (infp = fopen (file, "r")))
	  {
	     slrn_error ("File not found: %s--- message not posted.", file);
	     return -1;
	  }
	
	if (NULL == (outfp = slrn_open_home_file (Slrn_Save_Posts_File, "at",
						  save_post_file, 1)))
	  {
	     slrn_error ("Error saving to %s", save_post_file);
	     slrn_fclose (infp);
	     return -1;
	  }
	
	time (&now);
	fprintf (outfp, "From %s@%s %s", Slrn_User_Info.username, Slrn_User_Info.host, ctime(&now));
	fprintf (outfp, "From: %s@%s (%s)\n", Slrn_User_Info.username, Slrn_User_Info.host, Slrn_User_Info.realname);
	
	while (fgets (line, sizeof(line) - 1, infp) != NULL)
	  {
	     if ((*line == 'F')
		 && !strncmp ("From", line, 4)
		 && ((unsigned char)line[4] <= ' '))
	       {
		  putc ('>', outfp);
	       }
	     
	     fputs (line, outfp);
	  }
	fputs ("\n\n", outfp);
	slrn_fclose (infp);
	slrn_fclose (outfp);
     }
   
   if ((fp = fopen (file, "r")) == NULL)
     {
	slrn_error ("File not found: %s--- message not posted.", file);
	return -1;
     }
   
#if SLRN_HAS_MIME
   if (Slrn_Use_Mime)
     slrn_mime_scan_file (fp);
#endif
   
   if (Slrn_Post_Obj->po_start () < 0) return -1;
   
   if (Slrn_User_Info.username != NULL)
     Slrn_Post_Obj->po_printf ("Path: %s\r\n", Slrn_User_Info.username);
   
   Slrn_Post_Obj->po_printf ("From: %s@%s (%s)\r\n", Slrn_User_Info.username, Slrn_User_Info.host, Slrn_User_Info.realname);
   /* if (Slrn_User_Info.posting_host != NULL)
     * Slrn_Post_Obj->po_printf ("X-Posting-Host: %s\r\n", Slrn_User_Info.posting_host); */

   linep = line + 1;
   header = 1;
   while (fgets (linep, sizeof(line) - 1, fp) != NULL)
     {
	len = strlen (linep);
	if (len == 0) continue;
	if (header)
	  {
	     unsigned char *b;
	     char *white = linep;
	     
	     while ((*white == ' ') || (*white == '\t')) white++;
	     if (*white == '\n')
	       {
#ifdef SLRN_GEN_MSGID
		  if (has_messageid == 0)
		    {
		       Slrn_Last_Message_Id = msgid = slrn_create_message_id ();
		       if (msgid != NULL)
			 {
			    Slrn_Post_Obj->po_printf ("Message-Id: <slrn%s@%s>\r\n", msgid, Slrn_User_Info.posting_host);
			 }
		    }
#endif
#if SLRN_HAS_MIME
		  if (Slrn_Use_Mime)
		    slrn_mime_add_headers (0);   /* 0 --> Slrn_Post_Obj->po_puts */
#endif
		  Slrn_Post_Obj->po_printf ("X-Newsreader: slrn (%s %s)\r\n\r\n", Slrn_Version, 
			       SYSTEM_OS_NAME);
		  header = 0;
#if SLRN_HAS_MIME
		  if (Slrn_Use_Mime) fp = slrn_mime_encode (fp);
#endif
		  
		  continue;
	       }
	     
	     if (!slrn_case_strncmp ((unsigned char *)"Cc: ", 
				     (unsigned char *)linep, 4))
	       {
		  b = (unsigned char *) linep + 4;
		  b = (unsigned char *) slrn_skip_whitespace ((char *) b);
		  if (*b && (*b != ',')) perform_cc = 1;
		  continue;
	       }
	     if (is_empty_header (linep)) continue;
#ifdef SLRN_GEN_MSGID
	     if (!slrn_case_strncmp ((unsigned char *)"Message-Id: ",
				     (unsigned char *)linep, 12))
	       has_messageid = 1;
#endif	     
	     linep[len - 1] = 0;
#if SLRN_HAS_MIME
	     if (Slrn_Use_Mime)
	       slrn_mime_header_encode (linep, sizeof (line) - 1);
#endif
	  }
	
	
	if (linep[len - 1] == '\n')
	  {
	     len--;
	     linep[len] = 0;
	  }
	
	if (*linep == '.')
	  {
	     linep--;
	     *linep = '.';
	  }
	
	Slrn_Post_Obj->po_puts (linep);
	Slrn_Post_Obj->po_puts ("\r\n");
	
	linep = line + 1;
     }
   slrn_fclose (fp);
   
   if (Slrn_Post_Obj->po_end () == 0) slrn_message ("Posting...done.");
   else
     {
	slrn_smg_refresh ();
	sleep (2);
	slrn_clear_message (); SLang_Error = 0;
	rsp = slrn_get_response ("RrEeCc", "Select one: R-epost, E-dit, C-ancel");
	rsp |= 0x20;
	if (rsp == 'c') return -1;
	if ((rsp == 'e') && (slrn_edit_file (file, 1) < 0)) return -1;
	goto try_again;
     }
   
   if (perform_cc)
     {
	slrn_cc_file (file, to);
     }
   return 0;
}




int slrn_post (char *newsgroup, char *subj, char *dist)
{
   FILE *fp;
   char file[256];
   unsigned int header_lines;
   int ret;
   
   if (Slrn_Use_Tmpdir)
     {
	fp = slrn_open_tmpfile (file, "w");
     }
   else fp = slrn_open_home_file (SLRN_ARTICLE_FILENAME, "w", file, 0);
   
   if (fp == NULL)
     {
	slrn_error ("Unable to create %s.", file);
	return -1;
     }
   
   header_lines = 9;
   fprintf (fp, "Newsgroups: %s\nSubject: %s\n", newsgroup, subj);
   
   if (Slrn_User_Info.org != NULL)
     {
	header_lines++;
	fprintf (fp, "Organization: %s\n", Slrn_User_Info.org);
     }
   
   fprintf (fp, "Reply-To: %s\nFollowup-To: \n", Slrn_User_Info.replyto);
   fprintf (fp, "Keywords: \nSummary: \n");
   
   if (dist != NULL) fprintf (fp, "Distribution: %s\n", dist);
   
   header_lines += slrn_add_custom_headers (fp);

   fputs ("\n", fp);
   
   slrn_add_signature (fp);
   slrn_fclose (fp);
   
   if (slrn_edit_file (file, header_lines) >= 0)
     {
	ret = slrn_post_file (file, NULL);
     }
   else ret = -1;
   
   if (Slrn_Use_Tmpdir) (void) slrn_delete_file (file);
   return ret;
}



int slrn_add_custom_headers (FILE *fp)
{
   int n;
   char *s, *s1, ch, last_ch;
   
   if (Slrn_Custom_Headers == NULL) return 0;
   
   s = slrn_skip_whitespace (Slrn_Custom_Headers);
   if (*s == 0) return 0;
   
   s1 = s;
   n = 0;
   last_ch = 0;
   while ((ch = *s1) != 0)
     {
	if (ch == '\n') n++;
	last_ch = ch;
	s1++;
     }
   fputs (s, fp);
   if (last_ch != '\n')
     {
	fputs ("\n", fp);
	n++;
     }
   
   return n;
}

   



These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.