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