1 /* -*- mode: C; mode: fold; -*- */
2 /*
3  This file is part of SLRN.
4 
5  Copyright (c) 1994, 1999 John E. Davis <davis@space.mit.edu>
6 
7  This program is free software; you can redistribute it and/or modify it
8  under the terms of the GNU General Public License as published by the Free
9  Software Foundation; either version 2 of the License, or (at your option)
10  any later version.
11 
12  This program is distributed in the hope that it will be useful, but WITHOUT
13  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
15  more details.
16 
17  You should have received a copy of the GNU General Public License along
18  with this program; if not, write to the Free Software Foundation, Inc., 675
19  Mass Ave, Cambridge, MA 02139, USA.
20 */
21 #include "config.h"
22 #include "slrnfeat.h"
23 
24 /*{{{ Include Files */
25 
26 #include <stdio.h>
27 #include <string.h>
28 #include <stdarg.h>
29 #include <signal.h>
30 #include <ctype.h>
31 #include <errno.h>
32 #include <time.h>
33 
34 #ifdef HAVE_STDLIB_H
35 # include <stdlib.h>
36 #endif
37 
38 #ifdef HAVE_UNISTD_H
39 #include <unistd.h>
40 #endif
41 
42 #if !defined(VMS) && !defined(__WIN32__) && !defined(__NT__)
43 # define HAS_PASSWORD_CODE	1
44 # include <pwd.h>
45 #endif
46 
47 #ifdef VMS
48 # include "vms.h"
49 #else
50 # include <sys/types.h>
51 # include <sys/stat.h>
52 #endif
53 
54 #if defined(VMS) && defined(MULTINET)
55 # include "multinet_root:[multinet.include]netdb.h"
56 #else
57 # if defined(__NT__)
58 #  include <winsock.h>
59 # else
60 #  if defined(__WIN32__)
61 #   define Win32_Winsock
62 #   include <windows.h>
63 #  else
64 #   include <netdb.h>
65 #   ifndef h_errno
66 extern int h_errno;
67 #   endif
68 #  endif
69 # endif
70 #endif
71 
72 #ifdef HAVE_SYS_WAIT_H
73 # include <sys/wait.h>
74 #endif
75 
76 #ifdef NeXT
77 # undef WIFEXITED
78 # undef WEXITSTATUS
79 #endif
80 
81 #ifndef WEXITSTATUS
82 # define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
83 #endif
84 #ifndef WIFEXITED
85 # define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
86 #endif
87 
88 #include <slang.h>
89 #include "jdmacros.h"
90 
91 #include "misc.h"
92 #include "group.h"
93 #include "slrn.h"
94 #include "post.h"
95 #include "server.h"
96 #include "util.h"
97 #include "ttymsg.h"
98 #include "art.h"
99 #include "chmap.h"
100 
101 #if SLRN_HAS_MIME
102 #include "mime.h"
103 #endif
104 
105 #ifdef VMS
106 /* valid filname chars for unix equiv of vms filename */
107 # define VALID_FILENAME_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789$_-/"
108 # include "vms.h"
109 #endif
110 /*}}}*/
111 
112 /*{{{ Global Variables */
113 int Slrn_Full_Screen_Update = 1;
114 int Slrn_User_Wants_Confirmation = 1;
115 int Slrn_Message_Present = 0;
116 int Slrn_Abort_Unmodified = 0;
117 
118 #ifndef VMS
119 char *Slrn_SendMail_Command;
120 #endif
121 
122 char *Slrn_Editor;
123 char *Slrn_Editor_Post;
124 char *Slrn_Editor_Score;
125 char *Slrn_Editor_Mail;
126 #ifdef KANJI
127 int Slrn_Editor_Code = -1;
128 #endif
129 
130 Slrn_User_Info_Type Slrn_User_Info;
131 SLKeyMap_List_Type *Slrn_RLine_Keymap;
132 
133 /*}}}*/
134 /*{{{ Static Variables */
135 
136 static int Error_Present;
137 static SLang_RLine_Info_Type *Slrn_Keymap_RLI;
138 static char *Input_String;
139 static char *Input_String_Ptr;
140 static char *Input_Chars_Ptr;
141 static char *Input_Chars;
142 static int Beep_Pending;
143 /*}}}*/
144 
145 static void redraw_message (void);
146 static void redraw_mini_buffer (void);
147 
148 /*{{{ Screen Update Functions */
149 
slrn_smg_refresh(void)150 void slrn_smg_refresh (void)
151 {
152    if (Slrn_TT_Initialized & SLRN_SMG_INIT)
153      {
154 	slrn_push_suspension (0);
155 	if (Beep_Pending)
156 	  SLtt_beep ();
157 	Beep_Pending = 0;
158 	SLsmg_refresh ();
159 	slrn_pop_suspension ();
160      }
161 }
162 
163 
slrn_set_color(int color)164 void slrn_set_color (int color) /*{{{*/
165 {
166    SLsmg_set_color (color);
167 }
168 
169 /*}}}*/
170 
slrn_redraw(void)171 void slrn_redraw (void) /*{{{*/
172 {
173    if (Slrn_Batch) return;
174 
175    slrn_push_suspension (0);
176 
177    SLsmg_cls ();
178    Slrn_Full_Screen_Update = 1;
179 
180    redraw_message ();
181    slrn_update_screen ();
182    redraw_mini_buffer ();
183 
184    slrn_smg_refresh ();
185    slrn_pop_suspension ();
186 }
187 
188 /*}}}*/
189 
slrn_print_percent(int row,int col,SLscroll_Window_Type * w)190 void slrn_print_percent (int row, int col, SLscroll_Window_Type *w) /*{{{*/
191 {
192    int bot_showing;
193    unsigned int bot_number;
194 
195    SLsmg_erase_eol ();
196    SLsmg_gotorc (row, col);
197    SLsmg_printf ("-- %d/%d", w->line_num, w->num_lines);
198 
199    bot_number = w->line_num + (w->nrows - w->window_row) - 1;
200 
201    bot_showing = ((w->bot_window_line == NULL)
202 		  || (w->num_lines == bot_number));
203 
204    if (w->line_num == w->window_row + 1)
205      {
206 	SLsmg_write_string (bot_showing ? "  (All)" : "  (Top)" );
207      }
208    else if (bot_showing) SLsmg_write_string("  (Bot)");
209    else SLsmg_printf("  (%d%%)", (100 * bot_number) / w->num_lines);
210    SLsmg_erase_eol ();
211 }
212 
213 /*}}}*/
214 
slrn_update_top_status_line(void)215 void slrn_update_top_status_line (void) /*{{{*/
216 {
217    if (Slrn_Full_Screen_Update == 0) return;
218    SLsmg_gotorc (0, 0);
219    slrn_set_color (MENU_COLOR);
220 #ifdef KANJI
221    if (Slrn_Japanese_Messages) {
222 #if !defined(SLANG_JVERSION) && !defined(IBMPC_SYSTEM)
223      int charset = Slang_Current_Charset;
224 
225      Slang_Current_Charset = ISO2022JP;
226 #endif
227      SLsmg_printf ("\
228 slrn %s ** '?'�����ȥإ��, 'q'�ǽ�λ. ** ������: %s",
229 		   Slrn_Version,
230 		   Slrn_Server_Obj->sv_name);
231 #if !defined(SLANG_JVERSION) && !defined(IBMPC_SYSTEM)
232      Slang_Current_Charset = charset;
233 #endif
234    } else
235 #endif
236    SLsmg_printf ("\
237 slrn %s ** Press '?' for help, 'q' to quit. ** Server: %s",
238 		 Slrn_Version,
239 		 Slrn_Server_Obj->sv_name);
240    SLsmg_erase_eol ();
241    slrn_set_color (0);
242 }
243 
244 /*}}}*/
245 
246 /*}}}*/
247 /*{{{ Message/Error Functions */
248 
249 /* The first character is the color */
250 static char Message_Buffer[1024];
251 
redraw_message(void)252 static void redraw_message (void)
253 {
254 #ifdef KANJI
255 #if !defined(SLANG_JVERSION) && !defined(IBMPC_SYSTEM)
256    int charset = Slang_Current_Charset;
257 #endif
258 #endif
259    int color;
260    char *m, *mmax;
261 
262    if (Slrn_Batch) return;
263 
264    if (Slrn_Message_Present == 0)
265      return;
266 
267    slrn_push_suspension (0);
268 
269    SLsmg_gotorc (SLtt_Screen_Rows - 1, 0);
270 
271    color = Message_Buffer [0];
272    m = Message_Buffer + 1;
273 
274 #ifdef KANJI
275 #if !defined(SLANG_JVERSION) && !defined(IBMPC_SYSTEM)
276    if (Slrn_Japanese_Messages) {
277       Slang_Current_Charset = ISO2022JP;
278    }
279 #endif
280 #endif
281    while (1)
282      {
283 	mmax = slrn_strchr (m, 1);
284 	if (mmax == NULL)
285 	  mmax = m + strlen(m);
286 
287 	slrn_set_color (color);
288 	SLsmg_write_nchars (m, (unsigned int) (mmax - m));
289 	if (*mmax == 0)
290 	  break;
291 	mmax++;
292 	if (*mmax == 0)
293 	  break;
294 
295 	slrn_set_color (RESPONSE_CHAR_COLOR);
296 	SLsmg_write_nchars (mmax, 1);
297 	m = mmax + 1;
298      }
299 
300    SLsmg_erase_eol ();
301    slrn_set_color (0);
302 #ifdef KANJI
303 #if !defined(SLANG_JVERSION) && !defined(IBMPC_SYSTEM)
304    Slang_Current_Charset = charset;
305 #endif
306 #endif
307 
308    slrn_pop_suspension ();
309 }
310 
311 
vmessage_1(int color,char * fmt,va_list ap)312 static void vmessage_1 (int color, char *fmt, va_list ap)
313 {
314 #ifdef HAVE_VSNPRINTF
315    vsnprintf (Message_Buffer + 1, sizeof(Message_Buffer)-1, fmt, ap);
316 #else
317    vsprintf (Message_Buffer + 1, fmt, ap);
318 #endif
319 
320    Message_Buffer[0] = (char) color;
321    Slrn_Message_Present = 1;
322    redraw_message ();
323 }
324 
vmessage(FILE * fp,char * fmt,va_list ap)325 static void vmessage (FILE *fp, char *fmt, va_list ap)
326 {
327    if (Slrn_TT_Initialized & SLRN_SMG_INIT)
328      vmessage_1 (0, fmt, ap);
329    else
330      slrn_tty_vmessage (fp, fmt, ap);
331 }
332 
verror(char * fmt,va_list ap)333 static void verror (char *fmt, va_list ap)
334 {
335    if ((Slrn_TT_Initialized & SLRN_SMG_INIT) == 0)
336      {
337 	slrn_tty_vmessage (stderr, fmt, ap);
338      }
339    else if (Error_Present == 0)
340      {
341 	slrn_clear_message ();
342 	Error_Present = 1;
343 	Beep_Pending = 1;
344 	vmessage_1 (ERROR_COLOR, fmt, ap);
345 	SLang_flush_input ();
346      }
347 
348    if (SLang_Error == 0) SLang_Error = INTRINSIC_ERROR;
349 }
350 
351 /*}}}*/
slrn_clear_message(void)352 void slrn_clear_message (void) /*{{{*/
353 {
354    Slrn_Message_Present = Error_Present = 0;
355    /* SLang_Error = 0; */
356    Beep_Pending = 0;
357    SLKeyBoard_Quit = 0;
358 
359    if ((Slrn_TT_Initialized & SLRN_SMG_INIT) == 0)
360      return;
361 
362    slrn_push_suspension (0);
363    SLsmg_gotorc (SLtt_Screen_Rows - 1, 0);
364    SLsmg_erase_eol ();
365    *Message_Buffer = 0;
366    slrn_pop_suspension ();
367 }
368 
369 /*}}}*/
370 
slrn_va_message(char * fmt,va_list ap)371 void slrn_va_message (char *fmt, va_list ap)
372 {
373    if (Error_Present == 0)
374      vmessage (stderr, fmt, ap);
375 }
376 
slrn_message(char * fmt,...)377 int slrn_message (char *fmt, ...) /*{{{*/
378 {
379    va_list ap;
380 
381    if (Error_Present) return -1;
382    va_start(ap, fmt);
383    vmessage (stdout, fmt, ap);
384    va_end (ap);
385    return 0;
386 }
387 
388 /*}}}*/
389 
slrn_message_now(char * fmt,...)390 int slrn_message_now (char *fmt, ...) /*{{{*/
391 {
392    va_list ap;
393 
394    if (Error_Present) return -1;
395    va_start(ap, fmt);
396    vmessage (stdout, fmt, ap);
397    va_end (ap);
398    slrn_smg_refresh ();
399    Slrn_Message_Present = 0;
400    return 0;
401 }
402 
403 /*}}}*/
404 
slrn_error(char * fmt,...)405 void slrn_error (char *fmt, ...) /*{{{*/
406 {
407    va_list ap;
408 
409    va_start(ap, fmt);
410    verror (fmt, ap);
411    va_end (ap);
412 }
413 
414 /*}}}*/
415 
slrn_error_now(unsigned secs,char * fmt,...)416 void slrn_error_now (unsigned secs, char *fmt, ...) /*{{{*/
417 {
418    va_list ap;
419 
420    if (fmt != NULL)
421      {
422 	va_start(ap, fmt);
423 	verror (fmt, ap);
424 	va_end (ap);
425      }
426    slrn_smg_refresh ();
427    Slrn_Message_Present = 0;
428    if (secs) sleep (secs);
429 }
430 
431 /*}}}*/
432 
slrn_check_batch(void)433 int slrn_check_batch (void)
434 {
435    if (Slrn_Batch == 0) return 0;
436    slrn_error ("This function is not available in batch mode.");
437    return -1;
438 }
439 
440 /*}}}*/
441 
442 /*{{{ File Related Functions */
443 
444 
445 #ifdef VMS
446 /*{{{ VMS Filename fixup functions */
447 
vms_fix_name(char * name)448 static void vms_fix_name(char *name)
449 {
450    int idx, pos;
451 
452    pos = strspn(name, VALID_FILENAME_CHARS);
453    if (pos == strlen(name))
454      return;
455    for(idx=pos;idx<strlen(name);idx++)
456      if (!(isdigit(name[idx]) || isalpha(name[idx]) || (name[idx] == '$') || (name[idx] == '_') || (name[idx] == '-')
457 	   || (name[idx] == '/')))
458        name[idx] = '-';
459 }
460 
461 static char Copystr[SLRN_MAX_PATH_LEN];
vms_copyname1(char * name)462 static int vms_copyname1 (char *name)
463 {
464    strcpy(Copystr, name);
465    return(1);
466 }
467 
vms_copyname2(char * name,int type)468 static int vms_copyname2 (char *name, int type)
469 {
470    strcpy(Copystr, name);
471    return(1);
472 }
473 
474 /*}}}*/
475 #endif
476 
slrn_make_home_filename(char * name,char * file)477 void slrn_make_home_filename (char *name, char *file) /*{{{*/
478 {
479    char *home;
480 #ifndef VMS
481    if (slrn_is_absolute_path (name)
482        || ((name[0] == '.') && (name[1] == SLRN_PATH_SLASH_CHAR))
483 #if defined(IBMPC_SYSTEM)
484        || ((name[0] == '.') && (name[1] == '/'))
485 #endif
486        )
487      {
488 	strcpy (file, name);
489 #if defined(IBMPC_SYSTEM)
490 	slrn_os2_convert_path (file);
491 #endif
492 	return;
493      }
494 
495    if (NULL == (home = getenv ("SLRNHOME")))
496      home = getenv ("HOME");
497 
498    *file = 0;
499    slrn_dircat (home, name, file);
500 #else
501    char *cp, *cp1;
502    static char fname[SLRN_MAX_PATH_LEN];
503    char fn[SLRN_MAX_PATH_LEN], fn1[SLRN_MAX_PATH_LEN];
504    int rc, idx;
505 
506    strcpy (fn1, name);
507    if (NULL != slrn_strchr (name, ':'))
508      {
509 	strcpy (file, name);
510 	return;
511      }
512 
513    if (NULL == (home = getenv ("SLRNHOME")))
514      home = getenv ("HOME");
515 
516    *file = 0;
517    if (NULL != (cp = slrn_strchr (fn1, '/')))
518      {
519 # ifdef __DECC
520 	*cp = '\0'; cp++;
521 	cp1 = decc$translate_vms(home);
522 	if (cp1 == 0 || (int)cp1 == -1)
523 	  { /* error translating */ }
524 	else
525 	  {
526 	     strcpy(fname, cp1);
527 	     strcat(cp1, "/");
528  	  }
529 	strcat (cp1, fn1);
530 
531 	vms_fix_name (cp1);
532 
533 	rc = decc$to_vms(cp1, vms_copyname2, 0, 2);
534  	if (rc > 0)
535  	  {
536  	     strcpy(fname, Copystr);
537  	     rc = mkdir(fname, 0755);
538  	  }
539 	strcat(fname, cp);
540 # else
541 	*cp = '\0'; cp++;
542 	cp1 = shell$translate_vms(home);
543 	if (cp1 == 0 || (int)cp1 == -1)
544 	  { /* error translating */ }
545 	else
546  	  {
547 	     strcpy(fname, cp1);
548 	     strcat(cp1, "/");
549 	  }
550 	strcat (cp1, fn1);
551 
552 	vms_fix_name (cp1);
553 
554 	rc = shell$to_vms(cp1, vms_copyname2, 0, 2);
555 	if (rc > 0)
556 	  {
557 	     strcpy(fname, Copystr);
558 	     rc = mkdir(fname, 0755);
559 	  }
560 	strcat(fname, cp);
561 # endif
562 	strcpy(file,fname);
563      }
564    else
565      {
566 	if (home != NULL) strcpy(file, home);
567 	strcat(file, name);
568      }
569 #endif /* VMS */
570 }
571 
572 /*}}}*/
573 
slrn_make_home_dirname(char * name,char * dir)574 int slrn_make_home_dirname (char *name, char *dir) /*{{{*/
575 {
576    /* This needs modified to deal with VMS directory syntax */
577 #ifndef VMS
578    slrn_make_home_filename (name, dir);
579 #else
580    char *home, *cp;
581    char fn[SLRN_MAX_PATH_LEN];
582    static char fname[SLRN_MAX_PATH_LEN];
583    int rc, idx, len;
584 
585    if (NULL != slrn_strchr (name, ':'))
586      {
587 	strcpy (dir, name);
588 	return 0;
589      }
590    home = getenv ("HOME");
591    *dir = 0;
592    if (cp = strchr(name,'/'))
593      {
594 #ifdef __DECC
595 	cp = decc$translate_vms(home);
596 	if (cp == 0 || (int)cp == -1)
597 	  { /* error translating */ }
598 	else
599 	  {
600 	     strcpy(fname, cp);
601 	     strcat(cp, "/");
602 	  }
603 	strcat (cp, name);
604 	vms_fix_name (cp);
605 
606 	rc = decc$to_vms(cp, vms_copyname2, 0, 2);
607 	if (rc > 0)
608 	  {
609 	     strcpy(fname, Copystr);
610 	     rc = mkdir(fname, 0755);
611 	  }
612 #else
613 	if (shell$from_vms(home, vms_copyname1, 0))
614 	  {
615 	     if (Copystr != NULL) strcpy (fn, Copystr);
616 	     strcat(fn, "/");
617 	  }
618 	strcat (fn, name);
619 	vms_fix_name(fn);
620 	if (shell$to_vms(fn, vms_copyname1, 0))
621 	  strcpy(fname, Copystr);
622 #endif
623 	strcpy(dir,fname);
624      }
625    else
626      {
627 	if (home != NULL)
628 	 {
629 	  strcpy(dir, home);
630 	  len = strlen(dir) - 1;
631 	  if (dir[len] == ']')
632 	   {
633 	    dir[len] = '.';
634 	    strcat(dir, name);
635 	    strcat(dir, "]");
636 	   }
637 	  else
638 	    strcat(dir, name);
639 	 }
640 	else
641 	  strcat(dir, name);
642      }
643 #endif /* VMS */
644 
645    return 0;
646 }
647 
648 /*}}}*/
649 
make_random(void)650 static unsigned int make_random (void)
651 {
652    static unsigned long s;
653    static int init;
654 
655    if (init == 0)
656      {
657 	s = (unsigned long) time (NULL) + (unsigned long) getpid ();
658 	init = 1;
659      }
660 
661    s = s * 69069UL + 1013904243UL;
662 
663    /* The time has been added to make this number somewhat unpredictable
664     * based on the previous number.  The whole point of this is to foil
665     * any attempt of a hacker to determine the name of the _next_ temp
666     * file that slrn will create.
667     */
668    return (unsigned int) (s + (unsigned long) time (NULL));
669 }
670 
671 /* Note: This function should not create a file that is deleted when it
672  * is closed.
673  */
674 
slrn_open_tmpfile_in_dir(char * dir,char * file,char * mode)675 FILE *slrn_open_tmpfile_in_dir (char *dir, char *file, char *mode)
676 {
677    FILE *fp;
678    unsigned int len;
679    unsigned int i;
680    char buf[80];
681 
682 #ifndef VMS
683    if (2 != slrn_file_exists (dir))
684      return NULL;
685 #endif
686 
687 #if defined(IBMPC_SYSTEM)
688    sprintf (buf, "SLRN%04u", make_random ());
689 #else
690    sprintf (buf, "SLRN%X", make_random ());
691 #endif
692 
693    if (-1 == slrn_dircat (dir, buf, file))
694      return NULL;
695 
696 #if defined(IBMPC_SYSTEM)
697 # define MAX_TMP_FILE_NUMBER 999
698 #else
699 # define MAX_TMP_FILE_NUMBER 1024
700 #endif
701 
702    len = strlen (file);
703    for (i = 0; i < MAX_TMP_FILE_NUMBER; i++)
704      {
705 	sprintf (file + len, ".%u", i);
706 
707 	/* I wish this were an atomic operation but I do not know of a
708 	 * portable way to achieve that using standard C.
709 	 */
710 	if ((0 == slrn_file_exists (file))
711 	    && (NULL != (fp = fopen (file, mode))))
712 	  {
713 	     return fp;
714 	  }
715      }
716    return NULL;
717 }
718 
719 
720 
slrn_open_tmpfile(char * file,char * mode)721 FILE *slrn_open_tmpfile (char *file, char *mode) /*{{{*/
722 {
723    char *dir;
724 
725    dir = getenv ("TMP");
726    if ((dir == NULL) || (2 != slrn_file_exists (dir)))
727      dir = getenv ("TMPDIR");
728 
729    if ((dir == NULL) || (2 != slrn_file_exists (dir)))
730      {
731 #ifdef VMS
732 	dir = "SYS$LOGIN:";
733 #else
734 # if defined(IBMPC_SYSTEM)
735 	dir = ".";
736 # else
737 	dir = "/tmp";
738 # endif
739 #endif
740      }
741 
742    return slrn_open_tmpfile_in_dir (dir, file, mode);
743 }
744 
745 /*}}}*/
746 
slrn_open_home_file(char * name,char * mode,char * file,int create_flag)747 FILE *slrn_open_home_file (char *name, char *mode, char *file, int create_flag) /*{{{*/
748 {
749    slrn_make_home_filename (name, file);
750 
751 #ifdef VMS
752    if (create_flag)
753      {
754 	FILE *fp = fopen (file, mode, "fop=cif");
755 	if (fp == NULL) perror ("fopen");
756 	return fp;
757      }
758 #else
759    (void) create_flag;
760 #endif
761 
762    return fopen (file, mode);
763 }
764 
765 /*}}}*/
766 
slrn_mail_file(char * file,int edit,unsigned int editline,char * to,char * subject)767 int slrn_mail_file (char *file, int edit, unsigned int editline, char *to, char *subject) /*{{{*/
768 {
769    char buf [256 + 2 * SLRN_MAX_PATH_LEN];
770 #if defined(IBMPC_SYSTEM)
771    char outfile [SLRN_MAX_PATH_LEN];
772 #endif
773 
774    if (edit && (Slrn_Batch == 0))
775      {
776 	if (slrn_edit_file (Slrn_Editor_Mail, file, editline, 1) < 0) return -1;
777 
778 	while (1)
779 	  {
780 	     char rsp;
781 
782 #ifdef KANJI
783 	     rsp = slrn_get_response ("yYnNeE", Slrn_Japanese_Messages
784 				      ? "��å�����������ޤ���? \001Yes, \001No, \001Edit"
785 				      : "Mail the message? \001Yes, \001No, \001Edit");
786 #else
787 	     rsp = slrn_get_response ("yYnNeE", "Mail the message? \001Yes, \001No, \001Edit");
788 #endif
789 	     rsp |= 0x20;
790 	     if (rsp == 'n') return -1;
791 	     if (rsp == 'y') break;
792 	     if (slrn_edit_file (Slrn_Editor_Mail, file, 1, 0) < 0) return -1;
793 	  }
794      }
795 #ifdef KANJI
796    slrn_message_now (Slrn_Japanese_Messages
797 		     ? "������..."
798 		     : "Sending...");
799 #else
800    slrn_message_now ("Sending ...");
801 #endif
802 
803    if (-1 == slrn_save_file_to_mail_file (file, Slrn_Save_Replies_File, NULL))
804      return -1;
805 
806 #ifdef KANJI
807    /* editor �����Ф����ե�����Υ����ɤ� JIS ���Ѵ����� */
808    if (Slrn_Editor_Code != JIS
809        && slrn_conv_file(file, JIS) == -1) {
810      return -1;
811    }
812 #else
813    slrn_chmap_fix_file (file);
814 #endif
815 
816 #ifdef VMS
817    sprintf(buf, "%s\"%s\"", MAIL_PROTOCOL, to);
818    vms_send_mail( buf, subject, file );
819 #else
820    (void) to; (void) subject;
821 
822    /* What I need to do is to open the file and feed it line by line to the
823     * sendmail program.  This way I can strip out blank headers.
824     */
825    if (Slrn_Use_Mime)
826      {
827 	FILE *fp, *pp;
828 	int header = 1;
829 	char line[1024];
830 
831 	fp = fopen (file, "r");
832 	if (fp == NULL) return (-1);
833 
834 	slrn_mime_scan_file (fp);
835 # if defined(IBMPC_SYSTEM)
836 	pp = slrn_open_tmpfile (outfile, "w");
837 # else
838 	pp = slrn_popen (Slrn_SendMail_Command, "w");
839 # endif
840 	if (pp == NULL)
841 	  {
842 	     slrn_fclose (fp);
843 	     return (-1);
844 	  }
845 
846 	while (fgets (line, sizeof(line), fp) != NULL)
847 	  {
848 	     unsigned int len = strlen (line);
849 
850 	     if (len == 0) continue;
851 	     len--;
852 
853 	     if (line [len] == '\n') line [len] = 0;
854 
855 	     if (header)
856 	       {
857 		  if (line[0] == 0)
858 		    {
859 		       header = 0;
860 
861 		       slrn_mime_add_headers (pp);
862 		       fp = slrn_mime_encode (fp);
863 		    }
864 #ifdef KANJI
865 		  if (Slrn_Use_Mime == 1)
866 #endif
867 		  slrn_mime_header_encode (line, sizeof(line));
868 	       }
869 #if defined(KANJI) && !SLRN_GEN_FROM_EMAIL_HEADER
870 	       /* �ʤ����Τ����SunOS4.1.3JLE��sendmail�Ǥϡ�body����
871 		  From: �� Subject: ���ФƤ���Ȥ��������ʤ롣�ǡ�
872 		  news�ǤΥإå������˰�Ķ��������뤳�Ȥ�ƨ����
873 		  */
874 	     /* �嵭���н�Τ��ᡢFrom ������ '>' ������� */
875 	     if ((*line == 'F')
876 		 && !strncmp ("From", line, 4)
877 		 && (line[4] == ' ' || line[4] == ':'))
878 	       {
879 		  putc ('>', pp);
880 	       }
881 #endif
882 	     fputs (line, pp);
883 	     putc('\n', pp);
884 	  }
885 	slrn_fclose (fp);
886 #if defined(IBMPC_SYSTEM)
887 	slrn_fclose (pp);
888 	sprintf (buf, "%s %s", Slrn_SendMail_Command, outfile);
889 	slrn_posix_system (buf, 0);
890 #else
891 	slrn_pclose (pp);
892 #endif
893      }
894    else
895      {
896 #if defined(IBMPC_SYSTEM)
897 	sprintf (buf, "%s %s", Slrn_SendMail_Command, file);
898 #else
899 	sprintf (buf, "%s < %s", Slrn_SendMail_Command, file);
900 #endif
901 	slrn_posix_system (buf, 0);
902      }
903 #endif /* NOT VMS */
904 #ifdef KANJI
905    slrn_message (Slrn_Japanese_Messages
906 		 ? "������...��λ"
907 		 : "Sending...done");
908 #else
909    slrn_message ("Sending...done");
910 #endif
911    return 0;
912 }
913 
914 /*}}}*/
915 
916 #if SLRN_HAS_PIPING
_slrn_pclose(FILE * fp)917 int _slrn_pclose (FILE *fp)
918 {
919    int ret;
920 
921    ret = pclose (fp);
922    if (ret == 0) return ret;
923 
924 #if defined(WIFEXITED) && defined(WEXITSTATUS)
925    if ((ret != -1) && WIFEXITED(ret))
926      {
927 	ret = WEXITSTATUS(ret);
928      }
929 #endif
930    return ret;
931 }
932 #endif				       /* SLRN_HAS_PIPING */
933 
934 #if SLRN_HAS_PIPING
935 /* There appears to be no simply way of getting the command assocated with
936  * a pipe file descriptor.  Therefore, I will simply store them in a table.
937  */
938 typedef struct _Pipe_Cmd_Table_Type
939 {
940    char *cmd;
941    FILE *fp;
942    struct _Pipe_Cmd_Table_Type *next;
943 }
944 Pipe_Cmd_Table_Type;
945 
946 Pipe_Cmd_Table_Type *Pipe_Cmd_Table;
947 
store_pipe_cmd(char * cmd,FILE * fp)948 static int store_pipe_cmd (char *cmd, FILE *fp)
949 {
950    Pipe_Cmd_Table_Type *p;
951 
952    if (NULL == (cmd = SLang_create_slstring (cmd)))
953      return -1;
954 
955    p = (Pipe_Cmd_Table_Type *)slrn_malloc (sizeof (Pipe_Cmd_Table_Type), 1, 0);
956    if (p == NULL)
957      {
958 	SLang_free_slstring (cmd);
959 	return -1;
960      }
961    p->cmd = cmd;
962    p->fp = fp;
963    p->next = Pipe_Cmd_Table;
964    Pipe_Cmd_Table = p;
965    return 0;
966 }
967 
delete_pipe_cmd(FILE * fp)968 static void delete_pipe_cmd (FILE *fp)
969 {
970    Pipe_Cmd_Table_Type *last, *next;
971 
972    last = NULL;
973    next = Pipe_Cmd_Table;
974    while (next != NULL)
975      {
976 	if (next->fp == fp)
977 	  {
978 	     if (last != NULL)
979 	       last->next = next->next;
980 	     else
981 	       Pipe_Cmd_Table = next->next;
982 
983 	     SLang_free_slstring (next->cmd);
984 	     slrn_free ((char *) next);
985 	     return;
986 	  }
987 
988 	last = next;
989 	next = next->next;
990      }
991 
992    /* should not be reached */
993 }
994 
get_pipe_cmd(FILE * fp)995 static char *get_pipe_cmd (FILE *fp)
996 {
997    Pipe_Cmd_Table_Type *p;
998 
999    p = Pipe_Cmd_Table;
1000    while (p != NULL)
1001      {
1002 	if (p->fp == fp)
1003 	  return p->cmd;
1004 
1005 	p = p->next;
1006      }
1007 
1008    return "**UNKNOWN**";
1009 }
1010 #endif 				       /* SLRN_HAS_PIPING */
slrn_pclose(FILE * fp)1011 int slrn_pclose (FILE *fp) /*{{{*/
1012 {
1013 #if SLRN_HAS_PIPING
1014    int ret;
1015    if (fp == NULL) return -1;
1016 
1017    ret = _slrn_pclose (fp);
1018    if (ret)
1019      {
1020 	char buf[SLRN_MAX_PATH_LEN];
1021 	fprintf (stderr, "Command %s returned exit status %d.  Press RETURN.\n",
1022 		 get_pipe_cmd (fp), ret);
1023 	fgets (buf, sizeof(buf), stdin);
1024      }
1025 
1026    delete_pipe_cmd (fp);
1027 
1028    slrn_set_display_state (SLRN_TTY_INIT | SLRN_SMG_INIT);
1029    return 0;
1030 #else
1031    return -1;
1032 #endif
1033 }
1034 
1035 /*}}}*/
1036 
slrn_popen(char * cmd,char * mode)1037 FILE *slrn_popen (char *cmd, char *mode) /*{{{*/
1038 {
1039 #if SLRN_HAS_PIPING
1040    FILE *fp;
1041 
1042    slrn_set_display_state (0);
1043    fp = popen (cmd, mode);
1044 
1045    if (fp == NULL)
1046      {
1047 	char buf[256];
1048 	fprintf (stderr, "Command %s failed to run.  Press RETURN.\n", cmd);
1049 	fgets (buf, sizeof(buf), stdin);
1050 	slrn_set_display_state (SLRN_TTY_INIT | SLRN_SMG_INIT);
1051      }
1052    else (void) store_pipe_cmd (cmd, fp);
1053 
1054    return fp;
1055 #else
1056    return NULL;
1057 #endif
1058 }
1059 
1060 /*}}}*/
1061 
1062 
1063 /*}}}*/
1064 
create_edit_command(char * edit,char * cmd,char * file,unsigned int line)1065 static int create_edit_command (char *edit, char *cmd, char *file, unsigned int line) /*{{{*/
1066 {
1067    int d, s;
1068    char ch, *p = edit;
1069    /* Look for %d and %s */
1070 
1071    d = s = 0;
1072 
1073    while (0 != (ch = *p++))
1074      {
1075 	if (ch != '%') continue;
1076 	ch = *p;
1077 	if (!d && (ch == 'd'))
1078 	  {
1079 	     *p = 'u';		       /* map %d to %u (unsigned) */
1080 	     if (s == 0) d = 1; else d = 2;
1081 	  }
1082 	else if (!s && (ch == 's'))
1083 	  {
1084 	     if (d == 0) s = 1; else s = 2;
1085 	  }
1086 	else
1087 	  {
1088 	     slrn_error ("Invalid Editor definition.");
1089 	     return 0;
1090 	  }
1091 	p++;
1092      }
1093 
1094 #if defined(IBMPC_SYSTEM)
1095    /* Convert editor pathnames from / form to \\ form.  I wonder what
1096     * happens when the pathname contains a space.  Hmmm...
1097     */
1098    p = edit;
1099    while ((*p != ' ') && (*p != '\t') && (*p != 0))
1100      {
1101 	if (*p == '/') *p = '\\';
1102 	p++;
1103      }
1104 #endif
1105 
1106    /* No %d, %s */
1107 
1108    if ((d == 0) && (s == 0))
1109      {
1110 	sprintf (cmd, "%s %s", edit, file);
1111      }
1112    else if (d == 0)
1113      {
1114 	sprintf (cmd, edit, file);
1115      }
1116    else if (s == 0)
1117      {
1118 	sprintf (cmd, edit, (int) line);
1119 	strcat (edit, " ");
1120 	strcat (edit, file);
1121      }
1122    else /* d and s */
1123      {
1124 	if (d == 1)
1125 	  sprintf (cmd, edit, line, file);
1126 	else sprintf (cmd, edit, file, line);
1127      }
1128    return 1;
1129 }
1130 
1131 /*}}}*/
1132 
1133 /* This function returns -1 upon failure, -2 upon unmodified edit */
slrn_edit_file(char * editor,char * file,unsigned int line,int check_mtime)1134 int slrn_edit_file (char *editor, char *file, unsigned int line,
1135 		    int check_mtime) /*{{{*/
1136 {
1137    char buf[1024];
1138    char editbuf[1024];
1139    int ret;
1140    unsigned long mtime = 0;
1141    struct stat st;
1142 
1143    if (Slrn_Abort_Unmodified == 0)
1144      check_mtime = 0;
1145 
1146    if (editor == NULL)
1147      editor = Slrn_Editor;
1148 
1149    if ((editor == NULL)
1150        && (NULL == (editor = getenv("SLRN_EDITOR")))
1151        && (NULL == (editor = getenv("SLANG_EDITOR")))
1152        && (NULL == (editor = getenv("EDITOR")))
1153        && (NULL == (editor = getenv("VISUAL"))))
1154      {
1155 #if defined(VMS) || defined(__NT__) || defined(__MINGW32__)
1156 	editor = "edit";
1157 #else
1158 # if defined(__os2__)
1159 	editor = "e";
1160 # else
1161 #  ifdef __unix__
1162 	editor = "vi";
1163 #  endif
1164 # endif
1165 #endif
1166      }
1167 
1168 #ifdef KANJI
1169    if (slrn_conv_file(file, Slrn_Editor_Code) == -1) return (-1);
1170 #endif
1171    strcpy (editbuf, editor);
1172 
1173    if (0 == create_edit_command(editbuf, buf, file, line)) return -1;
1174 
1175    if (check_mtime
1176        && (0 == stat (file, &st)))
1177      mtime = (unsigned long) st.st_mtime;
1178 
1179    ret = slrn_posix_system (buf, 1);
1180 
1181    /* Am I the only one who thinks this is a good idea?? */
1182    if (Slrn_TT_Initialized) while (SLang_input_pending (5))
1183      SLang_flush_input ();
1184 
1185    if (check_mtime
1186        && (ret != -1)
1187        && (0 == stat (file, &st))
1188        && (mtime == (unsigned long) st.st_mtime))
1189      {
1190 #ifdef KANJI
1191 	slrn_message (Slrn_Japanese_Messages
1192 		      ? "�ե����뤬��������Ƥ��ޤ���"
1193 		      : "File was not modified");
1194 #else
1195 	slrn_message ("File was not modified");
1196 #endif
1197 	ret = -2;
1198      }
1199 
1200    return ret;
1201 }
1202 
1203 /*}}}*/
1204 
1205 /*{{{ Get Input From User Related Functions */
1206 
rline_update(unsigned char * buf,int len,int col)1207 static void rline_update (unsigned char *buf, int len, int col) /*{{{*/
1208 {
1209    slrn_push_suspension (0);
1210    SLsmg_gotorc (SLtt_Screen_Rows - 1, 0);
1211    SLsmg_write_nchars ((char *) buf, len);
1212    SLsmg_erase_eol ();
1213    SLsmg_gotorc (SLtt_Screen_Rows - 1, col);
1214    slrn_smg_refresh ();
1215    slrn_pop_suspension ();
1216 }
1217 
1218 /*}}}*/
1219 
1220 /* If 1, redraw read_line.  If 2, redraw message */
1221 static int Reading_Input;
1222 
redraw_mini_buffer(void)1223 static void redraw_mini_buffer (void) /*{{{*/
1224 {
1225    if (Reading_Input == 1)
1226      SLrline_redraw (Slrn_Keymap_RLI);
1227    else if (Reading_Input == 2)
1228      redraw_message ();
1229 }
1230 
1231 /*}}}*/
1232 
init_readline(void)1233 static SLang_RLine_Info_Type *init_readline (void) /*{{{*/
1234 {
1235    unsigned char *buf;
1236    SLang_RLine_Info_Type *rli;
1237 
1238    rli = (SLang_RLine_Info_Type *) slrn_malloc (sizeof(SLang_RLine_Info_Type),
1239 						1, 1);
1240    if (rli == NULL)
1241      return NULL;
1242 
1243    if (NULL == (buf = (unsigned char *) slrn_malloc (256, 0, 1)))
1244      {
1245 	SLFREE (rli);
1246 	return NULL;
1247      }
1248 
1249    rli->buf = buf;
1250    rli->buf_len = 255;
1251    rli->tab = 8;
1252    rli->dhscroll = 20;
1253    rli->getkey = SLang_getkey;
1254    rli->tt_goto_column = NULL;
1255    rli->update_hook = rline_update;
1256 #ifdef SL_RLINE_BLINK_MATCH
1257    rli->flags |= SL_RLINE_BLINK_MATCH;
1258    rli->input_pending = SLang_input_pending;
1259 #endif
1260    if (SLang_init_readline (rli) < 0)
1261      {
1262 	SLFREE (rli);
1263 	SLFREE (buf);
1264 	rli = NULL;
1265      }
1266 
1267    return rli;
1268 }
1269 
1270 /*}}}*/
1271 
slrn_init_readline(void)1272 int slrn_init_readline (void) /*{{{*/
1273 {
1274    if ((Slrn_Keymap_RLI == NULL)
1275        && (NULL == (Slrn_Keymap_RLI = init_readline ())))
1276      return -1;
1277 
1278    Slrn_RLine_Keymap = Slrn_Keymap_RLI->keymap;
1279 
1280    return 0;
1281 }
1282 
1283 /*}}}*/
1284 
read_from_input_string(char * str)1285 static int read_from_input_string (char *str)
1286 {
1287    char *s;
1288 
1289    if (Input_String == NULL) return -1;
1290 
1291    s = slrn_strchr (Input_String_Ptr, '\n');
1292    if (s != NULL)
1293      *s = 0;
1294 
1295    strncpy (str, Input_String_Ptr, 255);
1296    str[255] = 0;
1297 
1298    if (s == NULL)
1299      {
1300 	SLFREE (Input_String);
1301 	Input_String_Ptr = Input_String = NULL;
1302      }
1303    else Input_String_Ptr = s + 1;
1304 
1305    return strlen (str);
1306 }
1307 
1308 /* s could be NULL.  If so, input string is cleared. */
slrn_set_input_string(char * s)1309 void slrn_set_input_string (char *s)
1310 {
1311    slrn_free (Input_String);
1312    Input_String = s;
1313    Input_String_Ptr = s;
1314 }
1315 
read_from_input_char(void)1316 static char read_from_input_char (void)
1317 {
1318    if (Input_Chars_Ptr == NULL)
1319      return 0;
1320 
1321    if (*Input_Chars_Ptr == 0)
1322      {
1323 	slrn_set_input_chars (NULL);
1324 	return 0;
1325      }
1326 
1327    return *Input_Chars_Ptr++;
1328 }
1329 
slrn_set_input_chars(char * s)1330 void slrn_set_input_chars (char *s)
1331 {
1332    slrn_free (Input_Chars);
1333    Input_Chars = s;
1334    Input_Chars_Ptr = s;
1335 }
1336 
generic_read_input(char * prompt,char * dfl,char * str,int trim_flag,int no_echo,int point)1337 static int generic_read_input (char *prompt, char *dfl, char *str, int trim_flag,
1338 			       int no_echo, int point) /*{{{*/
1339 {
1340    int i;
1341    int tt_init_state;
1342    char prompt_buf[256];
1343    unsigned int len;
1344    int save_slang_error;
1345 #ifdef KANJI
1346 #if !defined(SLANG_JVERSION) && !defined(IBMPC_SYSTEM)
1347   int charset = Slang_Current_Charset;
1348 #endif
1349 #endif
1350 
1351    Slrn_Full_Screen_Update = 1;
1352 
1353    strncpy (prompt_buf, prompt, sizeof (prompt_buf));
1354    prompt_buf[sizeof(prompt_buf) - 1] = 0;
1355    len = strlen (prompt);
1356    if (len + 3 < sizeof (prompt_buf))
1357      {
1358 	if (len && (prompt[len - 1] != '?'))
1359 	  {
1360 	     strcpy (prompt_buf + len, ": ");
1361 	     len += 2;
1362 	  }
1363 	else
1364 	  {
1365 	     strcpy (prompt_buf + len, " ");
1366 	     len++;
1367 	  }
1368      }
1369 
1370    if ((dfl != NULL) && *dfl)
1371      {
1372 	if (len + 13 + strlen (dfl) < sizeof (prompt_buf))
1373 	  {
1374 	     sprintf (prompt_buf + len,
1375 		      "(default: %s) ", dfl);
1376 	  }
1377 	else dfl = NULL;
1378      }
1379    prompt = prompt_buf;
1380 
1381    if ((str == NULL) && (dfl == NULL)) return -1;
1382 
1383    Slrn_Keymap_RLI->edit_width = SLtt_Screen_Cols - 1;
1384    Slrn_Keymap_RLI->prompt = prompt;
1385    *Slrn_Keymap_RLI->buf = 0;
1386 
1387    /* slrn_set_suspension (1); */
1388 
1389    if ((str != NULL) && *str)
1390      {
1391 	strcpy ((char *) Slrn_Keymap_RLI->buf, str);
1392 	if (point == 0)
1393 	  Slrn_Keymap_RLI->point = 0;
1394 	else
1395 	  Slrn_Keymap_RLI->point = strlen (str);
1396 
1397 	*str = 0;
1398      }
1399    if (str == NULL) str = dfl;
1400 
1401    i = read_from_input_string (str);
1402    if (i >= 0) return i;
1403 
1404    tt_init_state = Slrn_TT_Initialized;
1405 
1406    slrn_set_display_state (Slrn_TT_Initialized | SLRN_TTY_INIT);
1407 
1408    if (no_echo)
1409      {
1410 #ifdef SL_RLINE_NO_ECHO
1411 	Slrn_Keymap_RLI->flags |= SL_RLINE_NO_ECHO;
1412 #endif
1413      }
1414    else
1415      {
1416 #ifdef SL_RLINE_NO_ECHO
1417 	Slrn_Keymap_RLI->flags &= ~SL_RLINE_NO_ECHO;
1418 #endif
1419      }
1420 
1421    if (tt_init_state & SLRN_SMG_INIT)
1422      Slrn_Keymap_RLI->update_hook = rline_update;
1423    else
1424      Slrn_Keymap_RLI->update_hook = NULL;
1425 
1426    slrn_enable_mouse (0);
1427 
1428 
1429    save_slang_error = SLang_Error;
1430    SLang_Error = 0;
1431 
1432    Reading_Input = 1;
1433 #if defined(KANJI) && !defined(SLANG_JVERSION) && !defined(IBMPC_SYSTEM)
1434    if (Slrn_Japanese_Messages) {
1435      Slang_Current_Charset = ISO2022JP;
1436    }
1437    i = SLang_read_line (Slrn_Keymap_RLI);
1438    Slang_Current_Charset = charset;
1439 #else
1440    i = SLang_read_line (Slrn_Keymap_RLI);
1441 #endif
1442    Reading_Input = 0;
1443 
1444    slrn_enable_mouse (1);
1445 
1446    if ((i >= 0) && !SLang_Error && !SLKeyBoard_Quit)
1447      {
1448 	char *b = (char *) Slrn_Keymap_RLI->buf;
1449 
1450 	if (*b)
1451 	  {
1452 	     if (no_echo == 0) SLang_rline_save_line (Slrn_Keymap_RLI);
1453 	     if (trim_flag)
1454 	       {
1455 		  slrn_trim_string (b);
1456 		  b = slrn_skip_whitespace (b);
1457 	       }
1458 	  }
1459 	else if (dfl != NULL) b = dfl;
1460 
1461 	/* b could be equal to dfl and dfl could be equal to str.  If this is
1462 	 * the case, there is no need to perform the strcpy */
1463 	if (b != str) strcpy (str, b);
1464 	i = strlen (str);
1465      }
1466 
1467    if (SLKeyBoard_Quit) i = -1;
1468    SLKeyBoard_Quit = 0;
1469    SLang_Error = save_slang_error;
1470 
1471    slrn_set_display_state (tt_init_state);
1472 
1473    if (tt_init_state & SLRN_SMG_INIT)
1474      {
1475 	/* put cursor at edge of screen to comfort user */
1476 	SLsmg_gotorc (SLtt_Screen_Rows - 1, 0);
1477 	slrn_smg_refresh ();
1478      }
1479    else
1480      {
1481 	putc ('\n', stdout);
1482 	fflush (stdout);
1483      }
1484 
1485    /* slrn_set_suspension (0); */
1486    return i;
1487 }
1488 
1489 /*}}}*/
1490 
slrn_read_input(char * prompt,char * dfl,char * str,int trim_flag,int point)1491 int slrn_read_input (char *prompt, char *dfl, char *str, int trim_flag, int point)
1492 {
1493    return generic_read_input (prompt, dfl, str, trim_flag, 0, point);
1494 }
1495 
slrn_read_input_no_echo(char * prompt,char * dfl,char * str,int trim_flag,int point)1496 int slrn_read_input_no_echo (char *prompt, char *dfl, char *str, int trim_flag, int point)
1497 {
1498    return generic_read_input (prompt, dfl, str, trim_flag, 1, point);
1499 }
1500 
slrn_read_integer(char * prompt,int * dflt,int * np)1501 int slrn_read_integer (char *prompt, int *dflt, int *np) /*{{{*/
1502 {
1503    char sdfl_buf[32];
1504    char *sdfl = NULL;
1505    char str[256];
1506    int n;
1507 
1508    if (dflt != NULL)
1509      {
1510 	sprintf (sdfl_buf, "%d", *dflt);
1511 	sdfl = sdfl_buf;
1512      }
1513 
1514    *str = 0;
1515    if (-1 == (n = slrn_read_input (prompt, sdfl, str, 1, 0)))
1516      {
1517 	slrn_error ("Abort!");
1518 	return -1;
1519      }
1520 
1521    if (1 != sscanf(str, "%d", &n))
1522      {
1523 	slrn_error ("Integer expected.");
1524 	return -1;
1525      }
1526    *np = n;
1527    return 0;
1528 }
1529 
1530 /*}}}*/
1531 
slrn_get_response(char * valid_chars,char * str,...)1532 char slrn_get_response (char *valid_chars, char *str, ...) /*{{{*/
1533 {
1534    char ch;
1535    va_list ap;
1536    char *v;
1537 
1538    /* if (SLang_Error) return -1; */
1539    if (Error_Present)
1540      slrn_error_now (2, NULL);
1541 
1542    while (1)
1543      {
1544 	Slrn_Full_Screen_Update = 1;
1545 
1546 	ch = read_from_input_char ();
1547 
1548 	if (ch == 0)
1549 	  {
1550 	     if (Slrn_TT_Initialized == 0)
1551 	       {
1552 		  char buf[256];
1553 
1554 		  va_start(ap, str);
1555 		  slrn_tty_vmessage (stdout, str, ap);
1556 		  va_end(ap);
1557 
1558 		  *buf = 0;
1559 		  (void) fgets (buf, sizeof(buf), stdin);
1560 		  ch = *buf;
1561 	       }
1562 	     else
1563 	       {
1564 		  SLang_flush_input ();
1565 		  slrn_clear_message ();
1566 
1567 		  va_start(ap, str);
1568 		  vmessage_1 (0, str, ap);
1569 		  va_end(ap);
1570 
1571 		  slrn_smg_refresh ();
1572 
1573 		  Reading_Input = 2;
1574 		  ch = SLang_getkey ();
1575 		  Reading_Input = 0;
1576 
1577 		  slrn_clear_message ();
1578 		  SLang_Error = SLKeyBoard_Quit = 0;
1579 	       }
1580 	  }
1581 
1582 	v = valid_chars;
1583 	while (*v)
1584 	  {
1585 	     if (*v == ch) return ch;
1586 	     v++;
1587 	  }
1588 
1589 #ifdef KANJI
1590 	slrn_error_now (0, Slrn_Japanese_Messages
1591 			? "�Ѥʱ����Ǥ����⤦���١�"
1592 			: "Invalid response! Try again.");
1593 #else
1594 	slrn_error_now (0, "Invalid response! Try again.");
1595 #endif
1596 	if (Slrn_TT_Initialized & SLRN_TTY_INIT)
1597 	  {
1598 	     (void) SLang_input_pending (15);
1599 	  }
1600      }
1601 }
1602 
1603 /*}}}*/
slrn_get_yesno(int dflt,char * str,...)1604 int slrn_get_yesno (int dflt, char *str, ...) /*{{{*/
1605 {
1606    va_list ap;
1607    char buf[512];
1608    char ch, rsp;
1609    char *fmt;
1610 
1611    /* if (SLang_Error) return -1; */
1612 
1613    va_start(ap, str);
1614    (void) vsprintf(buf, str, ap);
1615    va_end(ap);
1616 
1617    if (dflt)
1618      {
1619 	ch = 'y';
1620 	fmt = "? [\001Y]es, \001No";
1621      }
1622    else
1623      {
1624 	ch = 'n';
1625 	fmt = "? \001Yes, [\001N]o";
1626      }
1627 
1628    strcat (buf, fmt);
1629    rsp = slrn_get_response ("yYnN\r", buf);
1630    if (rsp == '\r') rsp = ch;
1631    else rsp |= 0x20;
1632 
1633    if (rsp == 'n') return 0;
1634    return 1;
1635 }
1636 
1637 /*}}}*/
slrn_get_yesno_cancel(char * str,...)1638 int slrn_get_yesno_cancel (char *str, ...) /*{{{*/
1639 {
1640    va_list ap;
1641    char buf[512];
1642 
1643    if (SLang_Error) return -1;
1644 
1645    if (strlen (str) >= sizeof (buf) + 25)
1646      return -1;
1647 
1648    va_start(ap, str);
1649    (void) vsprintf(buf, str, ap);
1650    va_end(ap);
1651 
1652    strcat (buf, "? [\001Y]es, \001No, \001Cancel");
1653 
1654    switch (slrn_get_response ("\007yYnNcC\r", buf))
1655      {
1656       case '\r':
1657       case 'Y':
1658       case 'y':
1659 	return 1;
1660 
1661       case 'n':
1662       case 'N':
1663 	return 0;
1664 
1665       default:
1666 	return -1;
1667      }
1668 }
1669 
1670 /*}}}*/
1671 
slrn_get_mouse_rc(int * rp,int * cp)1672 void slrn_get_mouse_rc (int *rp, int *cp) /*{{{*/
1673 {
1674    int r, c;
1675 
1676    c = (unsigned char) SLang_getkey () - 32;
1677    r = (unsigned char) SLang_getkey () - 32;
1678    if (cp != NULL) *cp = c;
1679    if (rp != NULL) *rp = r;
1680 }
1681 
1682 /*}}}*/
1683 
1684 /*}}}*/
1685 
1686 /*{{{ Misc Regexp Utility Functions */
1687 
slrn_compile_regexp_pattern(char * pat)1688 SLRegexp_Type *slrn_compile_regexp_pattern (char *pat) /*{{{*/
1689 {
1690    static unsigned char compiled_pattern_buf [512];
1691    static SLRegexp_Type re;
1692 
1693    re.pat = (unsigned char *) pat;
1694    re.buf = compiled_pattern_buf;
1695    re.buf_len = sizeof (compiled_pattern_buf);
1696    re.case_sensitive = 0;
1697 
1698    if (0 != SLang_regexp_compile (&re))
1699      {
1700 	slrn_error ("Invalid regular expression or expression too long.");
1701 	return NULL;
1702      }
1703    return &re;
1704 }
1705 
1706 /*}}}*/
1707 
slrn_regexp_match(SLRegexp_Type * re,char * str)1708 unsigned char *slrn_regexp_match (SLRegexp_Type *re, char *str) /*{{{*/
1709 {
1710    unsigned int len;
1711 
1712    if ((str == NULL)
1713        || (re->min_length > (len = strlen (str))))
1714      return NULL;
1715 
1716    return SLang_regexp_match ((unsigned char *)str, len, re);
1717 }
1718 
1719 /*}}}*/
1720 
1721 /*}}}*/
1722 
slrn_is_fqdn(char * h)1723 int slrn_is_fqdn (char *h) /*{{{*/
1724 {
1725    char *p;
1726 
1727    /* Believe it or not, I have come across one system with a '(' character
1728     * as part of the hostname!!!  I suppose that I should also check for
1729     * other strange characters as well.  This is an issue since a message
1730     * id will be composed from the fqdn.  For that reason, such names will
1731     * be rejected.  Sigh.
1732     */
1733    if (NULL != slrn_strbrk (h, "~`!@#$%^&*()=+|\\[]{}/?;"))
1734      return 0;
1735 
1736    p = slrn_strchr (h, '.');
1737    if ((p == NULL) || (p == h))
1738      return 0;
1739 
1740    /* Make sure it does not end in a '.' */
1741    if (p [strlen(p)-1] == '.')
1742      return 0;
1743 
1744    return 1;
1745 }
1746 /*}}}*/
1747 
1748 /* Try to get a fully qualified domain name. */
get_hostname(void)1749 static char *get_hostname (void)
1750 {
1751    struct hostent *host_entry;
1752    char buf[MAX_HOST_NAME_LEN + 1];
1753 
1754    host_entry = NULL;
1755    if ((-1 == gethostname (buf, MAX_HOST_NAME_LEN))
1756        || (*buf == 0))
1757      return NULL;
1758 
1759    /* gethostname may not provide the full name so use gethostbyname
1760     * to get more information.  Why isn't there a simplified interface to
1761     * get the FQDN!!!!
1762     */
1763 #ifdef KANJI
1764    if (slrn_is_fqdn(buf) != 0) {
1765       return slrn_safe_strmalloc (buf);
1766    }
1767 #endif
1768    host_entry = gethostbyname (buf);
1769 
1770 #if defined(TRY_AGAIN) && !defined(MULTINET)
1771    if ((host_entry == NULL) && (h_errno == TRY_AGAIN))
1772      {
1773 	sleep (2);
1774 	host_entry = gethostbyname (buf);
1775      }
1776 #endif
1777 
1778    if ((host_entry != NULL)
1779        && (host_entry->h_name != NULL)
1780        && (host_entry->h_name[0] != 0))
1781      {
1782 	char **aliases;
1783 
1784 	if ((0 == slrn_is_fqdn ((char *)host_entry->h_name))
1785 	    && (NULL !=	(aliases = host_entry->h_aliases)))
1786 	  {
1787 	     while (*aliases != NULL)
1788 	       {
1789 		  if (slrn_is_fqdn (*aliases))
1790 		    return slrn_safe_strmalloc (*aliases);
1791 		  aliases++;
1792 	       }
1793 	  }
1794 
1795 	return slrn_safe_strmalloc ((char *)host_entry->h_name);
1796      }
1797 
1798    return slrn_safe_strmalloc (buf);
1799 }
1800 
1801 #ifdef OUR_HOSTNAME
1802 /* Returns a pointer to a statically allocated area */
get_host_from_filename(char * file)1803 static char *get_host_from_filename (char *file)
1804 {
1805    FILE *fp;
1806    char *host;
1807    static char line[MAX_HOST_NAME_LEN + 1];
1808 
1809    if (NULL == (fp = fopen (file, "r")))
1810      return NULL;
1811 
1812    host = NULL;
1813    if (NULL != fgets (line, sizeof (line), fp))
1814      {
1815 	slrn_trim_string (line);
1816 	if (slrn_is_fqdn (line))
1817 	  host = line;
1818      }
1819 
1820    fclose(fp);
1821    return host;
1822 }
1823 #endif				       /* OUR_HOSTNAME */
1824 
slrn_get_user_info(void)1825 void slrn_get_user_info (void) /*{{{*/
1826 {
1827    char *name, *host, *host1;
1828 #ifdef HAS_PASSWORD_CODE
1829    struct passwd *pw;
1830 #endif
1831 
1832    /* Fill in what is assumed to be non-NULL by rest of program. */
1833    Slrn_User_Info.followup_string = slrn_safe_strmalloc ("In article %m, %r wrote:");
1834    Slrn_User_Info.reply_string = slrn_safe_strmalloc ("In %n, you wrote:");
1835 
1836    Slrn_Courtesy_CC_Message = slrn_safe_strmalloc ("[This message has also been posted.]");
1837 
1838    /* Now get default values for rest. */
1839    host = get_hostname ();
1840    if (host != NULL)
1841      {
1842 	if (slrn_is_fqdn (host))
1843 	  Slrn_User_Info.posting_host = slrn_safe_strmalloc (host);
1844 #if defined(USE_DOMAIN_NAME) && defined(MY_DOMAIN_NAME)
1845 	else if (MY_DOMAIN_NAME != NULL)
1846 	  {
1847 	     char *my_domain_name;
1848 	     unsigned int len;
1849 
1850 	     my_domain_name = MY_DOMAIN_NAME;
1851 	     if (*my_domain_name == '.')
1852 	       my_domain_name++;
1853 
1854 	     len = strlen (host);
1855 	     host1 = slrn_safe_malloc (len + strlen (my_domain_name) + 2);
1856 	     strcpy (host1, host);
1857 	     host1[len] = '.';
1858 	     strcpy (host1 + len + 1, my_domain_name);
1859 	     slrn_free (host);
1860 	     host = host1;
1861 	  }
1862 #endif				       /* USE_DOMAIN_NAME */
1863      }
1864 
1865    /* Allow user chance to specify another hostname.  However, it will not
1866     * affect the posting host.
1867     */
1868    if ((NULL != (host1 = getenv ("HOSTNAME")))
1869        && (0 == slrn_is_fqdn (host1)))
1870      host1 = NULL;
1871 
1872    /* If a value was compiled in, use it. */
1873 #ifdef OUR_HOSTNAME
1874    if (host1 == NULL)
1875      {
1876 	host1 = OUR_HOSTNAME;
1877 	/* If the value is a file, read the file for the FQDN */
1878 	if (slrn_is_absolute_path (host1))
1879 	  host1 = get_host_from_filename (OUR_HOSTNAME);
1880      }
1881 #endif
1882 
1883    if ((host1 != NULL)
1884        && slrn_is_fqdn (host1))
1885      {
1886 	slrn_free (host);
1887 	host = slrn_safe_strmalloc (host1);
1888      }
1889 
1890    /* Finally!! */
1891    Slrn_User_Info.hostname = host;
1892 
1893 #ifdef VMS
1894    name = slrn_vms_getlogin();
1895 #else
1896    name = NULL;
1897 # ifdef HAS_PASSWORD_CODE
1898    /* I cannot use getlogin under Unix because some implementations
1899     * truncate the username to 8 characters.  Besides, I suspect that
1900     * it is equivalent to the following line.
1901     */
1902    pw = getpwuid (getuid ());
1903    if (pw != NULL)
1904      name = pw->pw_name;
1905 # endif
1906 #endif
1907 
1908    if (((name == NULL) || (*name == 0))
1909        && ((name = getenv("USER")) == NULL)
1910        && ((name = getenv("LOGNAME")) == NULL))
1911      name = "";
1912 
1913    Slrn_User_Info.username = slrn_safe_strmalloc (name);
1914    Slrn_User_Info.login_name = slrn_safe_strmalloc (name);
1915 
1916    if ((Slrn_User_Info.replyto = getenv ("REPLYTO")) == NULL)
1917      Slrn_User_Info.replyto = "";
1918    Slrn_User_Info.replyto = slrn_safe_strmalloc (Slrn_User_Info.replyto);
1919 
1920 #ifdef VMS
1921    Slrn_User_Info.realname = slrn_vms_fix_fullname(slrn_vms_get_uaf_fullname());
1922 #else
1923    if (((Slrn_User_Info.realname = getenv ("NAME")) == NULL)
1924 # ifdef HAS_PASSWORD_CODE
1925        && ((pw == NULL) || ((Slrn_User_Info.realname = pw->pw_gecos) == NULL))
1926 # endif
1927        )
1928      {
1929 	Slrn_User_Info.realname = "";
1930      }
1931 #endif
1932 
1933    Slrn_User_Info.realname = slrn_safe_strmalloc (Slrn_User_Info.realname);
1934 
1935    /* truncate at character used to delineate extra gecos fields */
1936    name = Slrn_User_Info.realname;
1937    while (*name && (*name != ',')) name++;
1938    *name = 0;
1939 
1940    Slrn_User_Info.org = getenv ("ORGANIZATION");
1941 #ifdef OUR_ORGANIZATION
1942    if (Slrn_User_Info.org == NULL) Slrn_User_Info.org = OUR_ORGANIZATION;
1943 #endif
1944    if (Slrn_User_Info.org != NULL)
1945      {
1946 	/* Check to see if this is an organization file. */
1947 	char orgbuf[512];
1948 	if (slrn_is_absolute_path (Slrn_User_Info.org))
1949 	  {
1950 	     FILE *fporg;
1951 	     if (NULL != (fporg = fopen (Slrn_User_Info.org, "r")))
1952 	       {
1953 		  if (NULL != fgets (orgbuf, sizeof (orgbuf) - 1, fporg))
1954 		    {
1955 		       unsigned int orglen = strlen (orgbuf);
1956 		       if (orglen && (orgbuf[orglen - 1] == '\n'))
1957 			 orgbuf[orglen - 1] = 0;
1958 		       Slrn_User_Info.org = orgbuf;
1959 		    }
1960 		  slrn_fclose (fporg);
1961 	       }
1962 	  }
1963 	Slrn_User_Info.org = slrn_safe_strmalloc (Slrn_User_Info.org);
1964      }
1965 
1966    Slrn_User_Info.signature = slrn_safe_strmalloc (SLRN_SIGNATURE_FILE);
1967 
1968 #if SLRN_HAS_MIME
1969 #ifdef KANJI
1970    Slrn_Mime_Display_Charset = slrn_safe_strmalloc (SLRN_DEFAULT_CHARSET);
1971 #else
1972    Slrn_Mime_Display_Charset = slrn_safe_strmalloc ("iso-8859-1");
1973 #endif
1974 #endif
1975 
1976 #ifdef SLRN_SENDMAIL_COMMAND
1977    Slrn_SendMail_Command = slrn_safe_strmalloc (SLRN_SENDMAIL_COMMAND);
1978 #endif
1979 }
1980 
1981 /*}}}*/
1982 
_slrn_strcat(char * a,char * b,unsigned int n)1983 static char *_slrn_strcat (char *a, char *b, unsigned int n)
1984 {
1985    unsigned int max;
1986    unsigned int len = strlen (a);
1987 
1988    n--;
1989 
1990    if (n > len)
1991      {
1992 	max = n - len;
1993 	strncpy (a + len, b, max);
1994 	a[n] = 0;
1995      }
1996    return a;
1997 }
1998 
1999 #ifdef KANJI
slrn_make_from_string(int code)2000 char *slrn_make_from_string (int code)
2001 #else
2002 char *slrn_make_from_string (void)
2003 #endif
2004 {
2005    char *username, *hostname, *realname;
2006    static char buf[256];
2007 
2008    *buf = 0;
2009 
2010 #if SLRN_HAS_SLANG
2011    if ((1 == SLang_run_hooks ("make_from_string_hook", 0))
2012        && (0 == SLang_pop_slstring (&username)))
2013      {
2014 	if (*username != 0)
2015 	  {
2016 	     _slrn_strcat (buf, username, sizeof (buf));
2017 	     SLang_free_slstring (username);
2018 #ifdef KANJI
2019 	     slrn_conv_string(buf, code);
2020 #endif
2021 	     return buf;
2022 	  }
2023 	SLang_free_slstring (username);
2024 	/* Drop through to default */
2025      }
2026 #endif
2027 
2028    if (NULL == (username = Slrn_User_Info.username))
2029      username = "";
2030 
2031    if (NULL == (hostname = Slrn_User_Info.hostname))
2032      hostname = "";
2033 
2034    if (NULL == (realname = Slrn_User_Info.realname))
2035      realname = "";
2036 
2037    /* Build string of the form "username@hostname (realname)" */
2038    _slrn_strcat (buf, username, sizeof(buf));
2039    _slrn_strcat (buf, "@", sizeof(buf));
2040    _slrn_strcat (buf, hostname, sizeof(buf));
2041    _slrn_strcat (buf, " (", sizeof(buf));
2042    _slrn_strcat (buf, realname, sizeof(buf));
2043    _slrn_strcat (buf, ")", sizeof(buf));
2044 
2045 #ifdef KANJI
2046    slrn_conv_string(buf, code);
2047 #endif
2048    return buf;
2049 }
2050 
2051