1 /* -*- mode: C; mode: fold; -*- */
2 /*
3 This file is part of SLRN.
4
5 Copyright (c) 1994, 1999, 2007-2016 John E. Davis <jed@jedsoft.org>
6 Copyright (c) 2001-2006 Thomas Schultz <tststs@gmx.de>
7
8 This program is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 2 of the License, or (at your option)
11 any later version.
12
13 This program is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 more details.
17
18 You should have received a copy of the GNU General Public License along
19 with this program; if not, write to the Free Software Foundation, Inc.,
20 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 */
22 #include "config.h"
23 #include "slrnfeat.h"
24
25 /*{{{ Include Files */
26
27 #include <stdio.h>
28 #include <string.h>
29 #include <stdarg.h>
30 #include <signal.h>
31 #include <ctype.h>
32 #include <errno.h>
33 #include <time.h>
34
35 #ifdef HAVE_STDLIB_H
36 # include <stdlib.h>
37 #endif
38
39 #ifdef HAVE_UNISTD_H
40 #include <unistd.h>
41 #endif
42
43 #if !defined(VMS) && !defined(__WIN32__) && !defined(__NT__)
44 # define HAS_PASSWORD_CODE 1
45 # include <pwd.h>
46 #endif
47
48 #ifdef VMS
49 # include "vms.h"
50 #else
51 # include <sys/types.h>
52 # include <sys/stat.h>
53 #endif
54
55 #ifdef HAVE_FCNTL_H
56 # include <fcntl.h>
57 #endif
58 #ifdef HAVE_SYS_FCNTL_H
59 # include <sys/fcntl.h>
60 #endif
61
62 #if defined(VMS) && defined(MULTINET)
63 # include "multinet_root:[multinet.include]netdb.h"
64 #else
65 # if defined(__NT__)
66 # include <winsock.h>
67 # else
68 # if defined(__WIN32__)
69 /* # define Win32_Winsock */
70 # define __USE_W32_SOCKETS
71 # include <windows.h>
72 # ifdef __MINGW32__
73 # include <process.h>
74 # endif
75 # else
76 # include <netdb.h>
77 # if !defined(h_errno) && !defined(__CYGWIN__)
78 extern int h_errno;
79 # endif
80 # endif
81 # endif
82 #endif
83
84 #ifdef HAVE_SYS_WAIT_H
85 # include <sys/wait.h>
86 #endif
87
88 #ifdef NeXT
89 # undef WIFEXITED
90 # undef WEXITSTATUS
91 #endif
92
93 #ifndef WEXITSTATUS
94 # define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
95 #endif
96 #ifndef WIFEXITED
97 # define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
98 #endif
99
100 #include <slang.h>
101 #include "jdmacros.h"
102
103 #include "misc.h"
104 #include "group.h"
105 #include "slrn.h"
106 #include "util.h"
107 #include "server.h"
108 #include "ttymsg.h"
109 #include "art.h"
110 #include "post.h"
111 #include "snprintf.h"
112 #include "slrndir.h"
113 #include "menu.h"
114 #include "hooks.h"
115 #include "startup.h"
116 #include "strutil.h"
117 #include "common.h"
118
119 #ifdef VMS
120 /* valid filname chars for unix equiv of vms filename */
121 # define VALID_FILENAME_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789$_-/"
122 # include "vms.h"
123 #endif
124 /*}}}*/
125
126 /*{{{ Global Variables */
127 int Slrn_Full_Screen_Update = 1;
128 int Slrn_User_Wants_Confirmation = SLRN_CONFIRM_ALL;
129 int Slrn_Message_Present = 0;
130 int Slrn_Abort_Unmodified = 0;
131 int Slrn_Mail_Editor_Is_Mua = 0;
132
133 #ifndef VMS
134 char *Slrn_SendMail_Command;
135 #endif
136
137 char *Slrn_Editor;
138 char *Slrn_Editor_Post;
139 char *Slrn_Editor_Score;
140 char *Slrn_Editor_Mail;
141 int Slrn_Editor_Uses_Mime_Charset = 0;
142
143 char *Slrn_Top_Status_Line;
144
145 Slrn_User_Info_Type Slrn_User_Info;
146 SLKeyMap_List_Type *Slrn_RLine_Keymap;
147 SLang_RLine_Info_Type *Slrn_Keymap_RLI;
148
149 /*}}}*/
150 /*{{{ Static Variables */
151
152 static int Error_Present;
153 static char *Input_String;
154 static char *Input_String_Ptr;
155 static char *Input_Chars_Ptr;
156 static char *Input_Chars;
157 static int Beep_Pending;
158 /*}}}*/
159
160 static void redraw_message (void);
161 static void redraw_mini_buffer (void);
162
163 /*{{{ Screen Update Functions */
164
slrn_smg_refresh(void)165 void slrn_smg_refresh (void)
166 {
167 if (Slrn_TT_Initialized & SLRN_SMG_INIT)
168 {
169 slrn_push_suspension (0);
170 if (Beep_Pending)
171 SLtt_beep ();
172 Beep_Pending = 0;
173 SLsmg_refresh ();
174 slrn_pop_suspension ();
175 }
176 }
177
slrn_set_color(int color)178 void slrn_set_color (int color) /*{{{*/
179 {
180 SLsmg_set_color (color);
181 }
182
183 /*}}}*/
184
slrn_redraw(void)185 void slrn_redraw (void) /*{{{*/
186 {
187 if (Slrn_Batch) return;
188
189 slrn_push_suspension (0);
190
191 SLsmg_cls ();
192 Slrn_Full_Screen_Update = 1;
193
194 redraw_message ();
195 slrn_update_screen ();
196 redraw_mini_buffer ();
197
198 slrn_smg_refresh ();
199 slrn_pop_suspension ();
200 }
201
202 /*}}}*/
203
204 /* theoretically, buf needs at least space for 66 characters */
slrn_print_percent(char * buf,SLscroll_Window_Type * w,int lines)205 char *slrn_print_percent (char *buf, SLscroll_Window_Type *w, int lines) /*{{{*/
206 {
207 if (lines)
208 {
209 sprintf (buf, "%d/%d", w->line_num, w->num_lines);
210 }
211 else
212 {
213 int bot_showing;
214 unsigned int bot_number;
215
216 bot_number = w->line_num + (w->nrows - w->window_row) - 1;
217 bot_showing = ((w->bot_window_line == NULL)
218 || (w->num_lines == bot_number));
219
220 if (w->line_num == w->window_row + 1)
221 slrn_strncpy (buf, bot_showing ? _("All") : _("Top"), 66);
222 else if (bot_showing)
223 slrn_strncpy (buf, _("Bot"), 66);
224 else
225 sprintf (buf, "%d%%", (100 * bot_number) / w->num_lines); /* safe */
226 }
227 return buf;
228 }
229 /*}}}*/
230
top_status_line_cb(char ch,void * data,int * len,int * color)231 static char *top_status_line_cb (char ch, void *data, int *len, int *color) /*{{{*/
232 {
233 static char buf[32];
234 char *retval = NULL;
235 time_t now;
236
237 (void) data; (void) color; /* we currently don't use these */
238
239 switch (ch)
240 {
241 case 'd':
242 time(&now);
243 if (0 != (*len = strftime (buf, sizeof(buf), "%x", localtime(&now))))
244 retval = buf;
245 break;
246
247 case 'n':
248 if (NULL != Slrn_Group_Current_Group)
249 retval = Slrn_Group_Current_Group->group_name;
250 break;
251
252 case 's':
253 retval = Slrn_Server_Obj->sv_name;
254 break;
255
256 case 't':
257 time(&now);
258 if (0 != (*len = strftime (buf, sizeof(buf), "%X", localtime(&now))))
259 retval = buf;
260 break;
261
262 case 'v':
263 retval = Slrn_Version_String;
264 break;
265
266 }
267 return retval == NULL ? "" : retval;
268 }
269 /*}}}*/
slrn_update_top_status_line(void)270 void slrn_update_top_status_line (void) /*{{{*/
271 {
272 char *fmt = Slrn_Top_Status_Line;
273
274 if (Slrn_Full_Screen_Update == 0) return;
275
276 if ((fmt == NULL) || (*fmt == 0))
277 fmt = _("slrn %v ** Press '?' for help, 'q' to quit. ** Server: %s");
278
279 slrn_custom_printf (fmt, top_status_line_cb, NULL, 0, MENU_COLOR);
280 }
281 /*}}}*/
282
283 /*}}}*/
284 /*{{{ Message/Error Functions */
285
skip_char(char * s,char * smax,int ignore_combining)286 static char *skip_char (char *s, char *smax, int ignore_combining)
287 {
288 if (s >= smax)
289 return s;
290
291 if (Slrn_UTF8_Mode == 0)
292 return s+1;
293
294 return (char *)SLutf8_skip_chars ((SLuchar_Type *)s, (SLuchar_Type *)smax, 1, NULL, ignore_combining);
295 }
296
297 /* The first character is the color */
298 static char Message_Buffer[1024];
299
redraw_message(void)300 static void redraw_message (void)
301 {
302 int color;
303 char *m, *mmax;
304
305 if (Slrn_Batch) return;
306
307 if (Slrn_Message_Present == 0)
308 return;
309
310 slrn_push_suspension (0);
311
312 SLsmg_gotorc (SLtt_Screen_Rows - 1, 0);
313
314 color = Message_Buffer [0];
315 m = Message_Buffer + 1;
316 mmax = m + strlen (m);
317
318 while (1)
319 {
320 char *m1 = slrn_strbyte (m, 1);
321 if (m1 == NULL)
322 m1 = mmax;
323
324 slrn_set_color (color);
325 SLsmg_write_nchars (m, (unsigned int) (m1 - m));
326 if (m1 == mmax)
327 break;
328 m1++;
329 if (m1 == mmax)
330 break;
331
332 slrn_set_color (RESPONSE_CHAR_COLOR);
333 m = m1;
334 m1 = skip_char (m, mmax, 1);
335 SLsmg_write_nchars (m, m1-m);
336 m = m1;
337 }
338
339 SLsmg_erase_eol ();
340 slrn_set_color (0);
341
342 slrn_pop_suspension ();
343 }
344
vmessage_1(int color,char * fmt,va_list ap)345 static void vmessage_1 (int color, char *fmt, va_list ap)
346 {
347 slrn_vsnprintf (Message_Buffer + 1, sizeof(Message_Buffer)-1, fmt, ap);
348
349 Message_Buffer[0] = (char) color;
350 Slrn_Message_Present = 1;
351 redraw_message ();
352 }
353
vmessage(FILE * fp,char * fmt,va_list ap)354 static void vmessage (FILE *fp, char *fmt, va_list ap)
355 {
356 if (Slrn_TT_Initialized & SLRN_SMG_INIT)
357 vmessage_1 (MESSAGE_COLOR, fmt, ap);
358 else
359 slrn_tty_vmessage (fp, fmt, ap);
360 }
361
log_error_message(char * fmt,va_list ap)362 static void log_error_message (char *fmt, va_list ap)
363 {
364 if (Slrn_Debug_Fp != NULL)
365 {
366 (void) vfprintf (Slrn_Debug_Fp, fmt, ap);
367 (void) fputs ("\n", Slrn_Debug_Fp);
368 (void) fflush (Slrn_Debug_Fp);
369 }
370 }
371
slrn_verror(char * fmt,va_list ap)372 void slrn_verror (char *fmt, va_list ap)
373 {
374 va_list ap1;
375
376 VA_COPY(ap1, ap);
377
378 if ((Slrn_TT_Initialized & SLRN_SMG_INIT) == 0)
379 {
380 slrn_tty_vmessage (stderr, fmt, ap);
381 }
382 else if (Error_Present == 0)
383 {
384 slrn_clear_message ();
385 Error_Present = 1;
386 Beep_Pending = 1;
387 vmessage_1 (ERROR_COLOR, fmt, ap);
388 SLang_flush_input ();
389 }
390
391 log_error_message (fmt, ap1);
392 va_end (ap1);
393
394 if (SLang_get_error () == 0) SLang_set_error (INTRINSIC_ERROR);
395 }
396
397 /*}}}*/
slrn_clear_message(void)398 void slrn_clear_message (void) /*{{{*/
399 {
400 Slrn_Message_Present = Error_Present = 0;
401 /* SLang_Error = 0; */
402 Beep_Pending = 0;
403 SLKeyBoard_Quit = 0;
404
405 if ((Slrn_TT_Initialized & SLRN_SMG_INIT) == 0)
406 return;
407
408 slrn_push_suspension (0);
409 SLsmg_gotorc (SLtt_Screen_Rows - 1, 0);
410 SLsmg_erase_eol ();
411 *Message_Buffer = 0;
412 slrn_pop_suspension ();
413 }
414
415 /*}}}*/
416
slrn_clear_error(void)417 void slrn_clear_error (void)
418 {
419 SLang_set_error (0);
420 slrn_clear_message ();
421 }
422
slrn_va_message(char * fmt,va_list ap)423 void slrn_va_message (char *fmt, va_list ap)
424 {
425 if (Error_Present == 0)
426 vmessage (stdout, fmt, ap);
427 }
428
slrn_message(char * fmt,...)429 int slrn_message (char *fmt, ...) /*{{{*/
430 {
431 va_list ap;
432
433 if (Error_Present) return -1;
434 va_start(ap, fmt);
435 vmessage (stdout, fmt, ap);
436 va_end (ap);
437 return 0;
438 }
439
440 /*}}}*/
441
slrn_message_now(char * fmt,...)442 int slrn_message_now (char *fmt, ...) /*{{{*/
443 {
444 va_list ap;
445
446 if (Error_Present) return -1;
447 va_start(ap, fmt);
448 vmessage (stdout, fmt, ap);
449 va_end (ap);
450 slrn_smg_refresh ();
451 Slrn_Message_Present = 0;
452 return 0;
453 }
454
455 /*}}}*/
456
slrn_error_now(unsigned secs,char * fmt,...)457 void slrn_error_now (unsigned secs, char *fmt, ...) /*{{{*/
458 {
459 va_list ap;
460
461 if (fmt != NULL)
462 {
463 va_start(ap, fmt);
464 slrn_verror (fmt, ap);
465 va_end (ap);
466 }
467 slrn_smg_refresh ();
468 Slrn_Message_Present = 0;
469 if (secs) slrn_sleep (secs);
470 }
471
472 /*}}}*/
473
474 /* Wrapper around the SLsmg routine.
475 * This writes n bytes (not necessarily screen characters), replacing
476 * unprintable 8bit chars with question marks.
477 */
478
479 /* Wrapper around the SLsmg routine. */
slrn_write_nbytes(char * s,unsigned int n)480 void slrn_write_nbytes (char *s, unsigned int n) /*{{{*/
481 {
482 unsigned char *s1, *smax;
483 unsigned int eight_bit;
484
485 if (Slrn_UTF8_Mode)
486 {
487 SLsmg_write_nchars (s, n);
488 return;
489 }
490
491 s1 = (unsigned char *) s;
492 smax = s1 + n;
493 eight_bit = SLsmg_Display_Eight_Bit;
494
495 while (s1 < smax)
496 {
497 if ((*s1 & 0x80) && (eight_bit > (unsigned int) *s1))
498 {
499 if (s != (char *) s1)
500 SLsmg_write_nchars (s, (unsigned int) ((char *)s1 - s));
501 SLsmg_write_char ('?');
502 s1++;
503 s = (char *) s1;
504 }
505 else s1++;
506 }
507
508 if (s != (char *)s1)
509 SLsmg_write_nchars (s, (unsigned int) ((char *)s1 - s));
510 }
511 /*}}}*/
512
513 /* generic function to display format strings;
514 * cb is called when a descriptor other than '%', '?' or 'g' is encountered */
slrn_custom_printf(char * fmt,PRINTF_CB cb,void * param,int row,int def_color)515 void slrn_custom_printf (char *fmt, PRINTF_CB cb, void *param, /*{{{*/
516 int row, int def_color)
517 {
518 char ch, *cond_end = NULL, *elsepart = NULL;
519
520 SLsmg_gotorc (row, 0);
521 slrn_set_color (def_color);
522
523 while ((ch = *fmt) != 0)
524 {
525 char *s, *smax, *p;
526 int color = def_color;
527 int len = -1, field_len = -1;
528 int justify, spaces = 0;
529
530 if (fmt == elsepart)
531 {
532 fmt = cond_end + 1; /* skip the '?' */
533 elsepart = cond_end = NULL;
534 continue;
535 }
536
537 if (ch != '%')
538 {
539 if ((NULL == (s = slrn_strbyte (fmt, '%'))) && (elsepart == NULL))
540 {
541 SLsmg_write_string (fmt);
542 break;
543 }
544 else
545 {
546 char *end;
547 if ((elsepart != NULL) && (s > elsepart)) end = elsepart;
548 else end = s;
549 SLsmg_write_nchars (fmt, end - fmt);
550 fmt = end;
551 continue;
552 }
553 }
554
555 fmt++;
556 ch = *fmt++;
557
558 if (ch == '?')
559 {
560 int column;
561 char *res;
562
563 if (((ch = *fmt++) == '\0') || (*fmt++ != '?') ||
564 (NULL == (cond_end = slrn_strbyte (fmt, '?'))))
565 break; /* syntax error; stop here */
566 if ((NULL == (elsepart = slrn_strbyte (fmt, '&'))) ||
567 (elsepart > cond_end))
568 elsepart = cond_end;
569
570 column = SLsmg_get_column (); /* callback could print something */
571 res = (cb)(ch, param, &len, &color);
572 SLsmg_gotorc (row, column);
573
574 if ((res == NULL) || (*res == '\0') ||
575 ((*res == '0' || isspace(*res)) && *(res+1) == '\0'))
576 {
577 fmt = elsepart + 1;
578 if (elsepart == cond_end) cond_end = NULL;
579 elsepart = cond_end;
580 }
581 continue;
582 }
583
584 s = NULL;
585
586 if (ch == '-')
587 {
588 justify = 1;
589 ch = *fmt++;
590 }
591 else if (ch == '*')
592 {
593 justify = 2;
594 ch = *fmt++;
595 }
596 else
597 justify = 0;
598
599 if (isdigit (ch))
600 {
601 field_len = 0;
602 do
603 {
604 field_len = 10 * field_len + (int) (ch - '0');
605 ch = *fmt++;
606 }
607 while (isdigit (ch));
608 }
609
610 switch (ch)
611 {
612 case 0:
613 break;
614
615 case '%':
616 s = "%";
617 len = 1;
618 break;
619
620 case 'g':
621 SLsmg_erase_eol ();
622 if (justify)
623 field_len = SLtt_Screen_Cols - field_len;
624 SLsmg_gotorc (row, field_len);
625 break;
626
627 default:
628 s = (cb)(ch, param, &len, &color);
629 break;
630 }
631
632 if (s == NULL)
633 continue;
634
635 if (color != def_color)
636 slrn_set_color (color);
637
638 /* In case of UTF-8 characters, it is important to distinguish between
639 * the length in bytes and the length in characters. */
640 smax = s + strlen (s);
641 len = slrn_screen_strlen (s, smax);
642 if (NULL != (p = slrn_strbyte (s, '\n')))
643 len = slrn_screen_strlen (s, p);
644
645 if (field_len != -1)
646 {
647 if (field_len > len)
648 spaces = field_len - len;
649 else
650 len = field_len;
651 }
652 if (justify)
653 {
654 int n;
655 if (justify == 1) n = 0; /* right justify */
656 else n = spaces - (spaces / 2); /* center */
657 while (spaces > n)
658 {
659 SLsmg_write_nchars (" ", 1);
660 spaces--;
661 }
662 }
663 SLsmg_write_nstring (s, len);
664 while (spaces)
665 {
666 SLsmg_write_nchars (" ", 1);
667 spaces--;
668 }
669 if (color != def_color)
670 slrn_set_color (def_color);
671 }
672
673 SLsmg_erase_eol ();
674 }
675 /*}}}*/
676
slrn_set_display_format(char ** formats,unsigned int num,char * entry)677 int slrn_set_display_format (char **formats, unsigned int num, char *entry) /*{{{*/
678 {
679 if (num >= SLRN_MAX_DISPLAY_FORMATS)
680 return -1;
681
682 if (formats[num] != NULL)
683 SLang_free_slstring (formats[num]);
684
685 if ((entry == NULL) || (*entry == 0))
686 {
687 formats[num] = NULL;
688 return 0;
689 }
690
691 if (NULL == (formats[num] = SLang_create_slstring (entry)))
692 return -1;
693
694 return 0;
695 }
696 /*}}}*/
697
slrn_toggle_format(char ** formats,unsigned int cur)698 unsigned int slrn_toggle_format (char **formats, unsigned int cur) /*{{{*/
699 {
700 unsigned int retval = cur;
701
702 if (Slrn_Prefix_Arg_Ptr != NULL)
703 {
704 retval = (unsigned int) *Slrn_Prefix_Arg_Ptr % SLRN_MAX_DISPLAY_FORMATS;
705 Slrn_Prefix_Arg_Ptr = NULL;
706 }
707 else retval = (retval + 1) % SLRN_MAX_DISPLAY_FORMATS;
708
709 while ((retval != cur) && (formats[retval] == NULL))
710 retval = (retval + 1) % SLRN_MAX_DISPLAY_FORMATS;
711
712 Slrn_Full_Screen_Update = 1;
713 return retval;
714 }
715 /*}}}*/
716
slrn_check_batch(void)717 int slrn_check_batch (void)
718 {
719 if (Slrn_Batch == 0) return 0;
720 slrn_error (_("This function is not available in batch mode."));
721 return -1;
722 }
723
724 /*}}}*/
725
726 /*{{{ File Related Functions */
727
728 #ifdef VMS
729 /*{{{ VMS Filename fixup functions */
730
vms_fix_name(char * name)731 static void vms_fix_name(char *name)
732 {
733 int idx, pos;
734
735 pos = strspn(name, VALID_FILENAME_CHARS);
736 if (pos == strlen(name))
737 return;
738 for(idx=pos;idx<strlen(name);idx++)
739 if (!(isdigit(name[idx]) || isalpha(name[idx]) || (name[idx] == '$') || (name[idx] == '_') || (name[idx] == '-')
740 || (name[idx] == '/')))
741 name[idx] = '-';
742 }
743
744 static char Copystr[SLRN_MAX_PATH_LEN];
vms_copyname1(char * name)745 static int vms_copyname1 (char *name)
746 {
747 slrn_strncpy(Copystr, name, sizeof (Copystr));
748 return(1);
749 }
750
vms_copyname2(char * name,int type)751 static int vms_copyname2 (char *name, int type)
752 {
753 slrn_strncpy(Copystr, name, sizeof (Copystr));
754 return(1);
755 }
756
757 /*}}}*/
758 #endif
759
slrn_make_home_filename(char * name,char * file,size_t n)760 void slrn_make_home_filename (char *name, char *file, size_t n) /*{{{*/
761 {
762 char *home;
763 #ifndef VMS
764 if (slrn_is_absolute_path (name)
765 || ((name[0] == '.') &&
766 ((name[1] == SLRN_PATH_SLASH_CHAR) ||
767 ((name[1] == '.') && (name[2] == SLRN_PATH_SLASH_CHAR))))
768 #if defined(IBMPC_SYSTEM)
769 || ((name[0] == '.') &&
770 ((name[1] == '/') ||
771 ((name[1] == '.') && name[2] == '/')))
772 #endif
773 )
774 {
775 #ifdef __CYGWIN__
776 if (slrn_cygwin_convert_path (name, file, n))
777 #endif
778 slrn_strncpy (file, name, n);
779 #if defined(IBMPC_SYSTEM) && !defined(__CYGWIN__)
780 slrn_os2_convert_path (file);
781 #endif
782 return;
783 }
784
785 if (NULL == (home = getenv ("SLRNHOME")))
786 home = getenv ("HOME");
787
788 *file = 0;
789 slrn_dircat (home, name, file, n);
790 #else /* VMS */
791 char *cp, *cp1;
792 static char fname[SLRN_MAX_PATH_LEN];
793 char fn[SLRN_MAX_PATH_LEN], fn1[SLRN_MAX_PATH_LEN];
794 int rc, idx;
795
796 slrn_strncpy (fn1, name, sizeof (fn1));
797 if (NULL != slrn_strbyte (name, ':'))
798 {
799 slrn_strncpy (file, name, n);
800 return;
801 }
802
803 if (NULL == (home = getenv ("SLRNHOME")))
804 home = getenv ("HOME");
805
806 *file = 0;
807 if (NULL != (cp = slrn_strbyte (fn1, '/')))
808 {
809 # ifdef __DECC
810 *cp = '\0'; cp++;
811 cp1 = decc$translate_vms(home);
812 if (cp1 == 0 || (int)cp1 == -1)
813 { /* error translating */ }
814 else
815 {
816 slrn_strncpy(fname, cp1, sizeof (fname));
817 strcat(cp1, "/"); /* safe ? */
818 }
819 strcat (cp1, fn1); /* safe ? */
820
821 vms_fix_name (cp1);
822
823 rc = decc$to_vms(cp1, vms_copyname2, 0, 2);
824 if (rc > 0)
825 {
826 slrn_strncpy(fname, Copystr, sizeof (fname));
827 rc = mkdir(fname, 0755);
828 }
829 if (strlen (fname) + strlen (cp) < sizeof (fname))
830 strcat(fname, cp); /* safe */
831 # else
832 *cp = '\0'; cp++;
833 cp1 = shell$translate_vms(home);
834 if (cp1 == 0 || (int)cp1 == -1)
835 { /* error translating */ }
836 else
837 {
838 slrn_strncpy(fname, cp1, sizeof (fname));
839 strcat(cp1, "/"); /* safe ? */
840 }
841 strcat (cp1, fn1); /* safe ? */
842
843 vms_fix_name (cp1);
844
845 rc = shell$to_vms(cp1, vms_copyname2, 0, 2);
846 if (rc > 0)
847 {
848 slrn_strncpy(fname, Copystr, sizeof (fname));
849 rc = mkdir(fname, 0755);
850 }
851 if (strlen (fname) + strlen (cp) < sizeof (fname))
852 strcat(fname, cp); /* safe */
853 # endif
854 slrn_strncpy (file, fname, n);
855 }
856 else
857 {
858 if (home != NULL) slrn_strncpy(file, home, n);
859 if (strlen (file) + strlen (name) < n)
860 strcat (file, name); /* safe */
861 }
862 #endif /* VMS */
863 }
864
865 /*}}}*/
866
slrn_make_home_dirname(char * name,char * dir,size_t n)867 void slrn_make_home_dirname (char *name, char *dir, size_t n) /*{{{*/
868 {
869 /* This needs modified to deal with VMS directory syntax */
870 #ifndef VMS
871 slrn_make_home_filename (name, dir, n);
872 #else
873 char *home, *cp;
874 char fn[SLRN_MAX_PATH_LEN];
875 static char fname[SLRN_MAX_PATH_LEN];
876 int rc, idx, len;
877
878 if (NULL != slrn_strbyte (name, ':'))
879 {
880 slrn_strncpy (dir, name, n);
881 return;
882 }
883 home = getenv ("HOME");
884 *dir = 0;
885 if (cp = strbyte(name,'/'))
886 {
887 #ifdef __DECC
888 cp = decc$translate_vms(home);
889 if (cp == 0 || (int)cp == -1)
890 { /* error translating */ }
891 else
892 {
893 slrn_strncpy(fname, cp, sizeof (fname));
894 strcat(cp, "/"); /* safe ? */
895 }
896 strcat (cp, name); /* safe ? */
897 vms_fix_name (cp);
898
899 rc = decc$to_vms(cp, vms_copyname2, 0, 2);
900 if (rc > 0)
901 {
902 slrn_strncpy(fname, Copystr, sizeof (fname));
903 rc = mkdir(fname, 0755);
904 }
905 #else
906 if (shell$from_vms(home, vms_copyname1, 0))
907 {
908 if (Copystr != NULL)
909 slrn_strncpy (fn, Copystr, sizeof (fn));
910 if (strlen (fn) + 1 < sizeof (fn))
911 strcat(fn, "/"); /* safe */
912 }
913 if (strlen (fn) + strlen (name) < sizeof (fn))
914 strcat (fn, name); /* safe */
915 vms_fix_name(fn);
916 if (shell$to_vms(fn, vms_copyname1, 0))
917 slrn_strncpy (fname, Copystr, sizeof (fname));
918 #endif
919 slrn_strncpy (dir, fname, n);
920 }
921 else
922 {
923 if (home != NULL)
924 {
925 slrn_strncpy(dir, home, n);
926 len = strlen(dir) - 1;
927 if (dir[len] == ']')
928 {
929 if (len + 3 + strlen (name) < n)
930 {
931 dir[len] = '.';
932 strcat(dir, name); /* safe */
933 strcat(dir, "]"); /* safe */
934 }
935 }
936 else if (len + 1 + strlen (name) < n)
937 strcat(dir, name); /* safe */
938 }
939 else if (strlen (dir) + strlen (name) < n)
940 strcat(dir, name); /* safe */
941 }
942 #endif /* VMS */
943
944 return;
945 }
946
947 /*}}}*/
948
make_random(void)949 static unsigned int make_random (void)
950 {
951 static unsigned long s;
952 static int init;
953
954 if (init == 0)
955 {
956 s = (unsigned long) time (NULL) + (unsigned long) getpid ();
957 init = 1;
958 }
959
960 s = s * 69069UL + 1013904243UL;
961
962 /* The time has been added to make this number somewhat unpredictable
963 * based on the previous number. The whole point of this is to foil
964 * any attempt of a hacker to determine the name of the _next_ temp
965 * file that slrn will create.
966 */
967 return (unsigned int) (s + (unsigned long) time (NULL));
968 }
969
970 /* Note: This function should not create a file that is deleted when it
971 * is closed.
972 */
973
slrn_open_tmpfile_in_dir(char * dir,char * file,size_t n)974 FILE *slrn_open_tmpfile_in_dir (char *dir, char *file, size_t n)
975 {
976 FILE *fp;
977 unsigned int len;
978 unsigned int i;
979 char buf[80];
980
981 #ifndef VMS
982 if (2 != slrn_file_exists (dir))
983 return NULL;
984 #endif
985
986 #if defined(IBMPC_SYSTEM)
987 slrn_snprintf (buf, sizeof (buf), "SLRN%04u", make_random ());
988 #else
989 slrn_snprintf (buf, sizeof (buf), "SLRN%X", make_random ());
990 #endif
991
992 if (-1 == slrn_dircat (dir, buf, file, n))
993 return NULL;
994
995 #if defined(IBMPC_SYSTEM)
996 # define MAX_TMP_FILE_NUMBER 999
997 #else
998 # define MAX_TMP_FILE_NUMBER 1024
999 #endif
1000
1001 len = strlen (file);
1002 for (i = 0; i < MAX_TMP_FILE_NUMBER; i++)
1003 {
1004 int fd;
1005
1006 if (len + 5 < n)
1007 sprintf (file + len, ".%u", i); /* safe */
1008 else if (i)
1009 break;
1010
1011 fd = open (file, O_WRONLY | O_CREAT | O_EXCL, S_IREAD | S_IWRITE);
1012 if (fd != -1)
1013 {
1014 if (NULL == (fp = fdopen (fd, "w")))
1015 close (fd);
1016 else
1017 return fp;
1018 }
1019 }
1020 return NULL;
1021 }
1022
slrn_open_tmpfile(char * file,size_t n)1023 FILE *slrn_open_tmpfile (char *file, size_t n) /*{{{*/
1024 {
1025 char *dir;
1026
1027 dir = getenv ("TMP");
1028 if ((dir == NULL) || (2 != slrn_file_exists (dir)))
1029 dir = getenv ("TMPDIR");
1030
1031 if ((dir == NULL) || (2 != slrn_file_exists (dir)))
1032 {
1033 #ifdef VMS
1034 dir = "SYS$LOGIN:";
1035 #else
1036 # if defined(IBMPC_SYSTEM)
1037 dir = ".";
1038 # else
1039 dir = "/tmp";
1040 # endif
1041 #endif
1042 }
1043
1044 return slrn_open_tmpfile_in_dir (dir, file, n);
1045 }
1046
1047 /*}}}*/
1048
slrn_open_home_file(char * name,char * mode,char * file,size_t n,int create_flag)1049 FILE *slrn_open_home_file (char *name, char *mode, char *file, /*{{{*/
1050 size_t n, int create_flag)
1051 {
1052 char filebuf[SLRN_MAX_PATH_LEN];
1053
1054 if (file == NULL)
1055 {
1056 file = filebuf;
1057 n = sizeof (filebuf);
1058 }
1059
1060 slrn_make_home_filename (name, file, n);
1061
1062 #ifdef VMS
1063 if (create_flag)
1064 {
1065 FILE *fp = fopen (file, mode, "fop=cif");
1066 if (fp == NULL) perror ("fopen");
1067 return fp;
1068 }
1069 #else
1070 (void) create_flag;
1071 #endif
1072
1073 if (2 == slrn_file_exists (file)) /* don't open directories */
1074 return NULL;
1075 return fopen (file, mode);
1076 }
1077
1078 /*}}}*/
1079
slrn_open_home_vfile(char * name,char * file,size_t n)1080 VFILE *slrn_open_home_vfile (char *name, char *file, size_t n)
1081 {
1082 char filebuf[SLRN_MAX_PATH_LEN];
1083
1084 if (file == NULL)
1085 {
1086 file = filebuf;
1087 n = sizeof (filebuf);
1088 }
1089
1090 slrn_make_home_filename (name, file, n);
1091
1092 return vopen (file, 4096, 0);
1093 }
1094
1095 /*}}}*/
1096
slrn_mail_file(char * file,int edit,unsigned int editline,char * to,char * subject)1097 int slrn_mail_file (char *file, int edit, unsigned int editline, char *to, char *subject) /*{{{*/
1098 {
1099 FILE *pp;
1100 Slrn_Article_Type *a;
1101 #if defined(IBMPC_SYSTEM)
1102 char *buf;
1103 char outfile [SLRN_MAX_PATH_LEN];
1104 #endif
1105
1106 if (edit && (Slrn_Batch == 0))
1107 {
1108 if (slrn_edit_file (Slrn_Editor_Mail, file, editline, 1) < 0) return -1;
1109 if (Slrn_Mail_Editor_Is_Mua) return 0;
1110
1111 while (1)
1112 {
1113 char rsp;
1114 /* Note to translators: "yY" is for "yes", "nN" for "no", "eE" for "edit".
1115 * Do not change the length of this string. You cannot use any of the
1116 * default characters for different fields. */
1117 char *responses=_("yYnNeE");
1118
1119 if (strlen (responses) != 6)
1120 responses = "";
1121 rsp = slrn_get_response ("yYnNeE", responses, _("Mail the message? \001Yes, \001No, \001Edit"));
1122 rsp = slrn_map_translated_char ("yYnNeE", responses, rsp) | 0x20;
1123 if (rsp == 'n') return -1;
1124 if (rsp == 'y') break;
1125 if (slrn_edit_file (Slrn_Editor_Mail, file, 1, 0) < 0) return -1;
1126 }
1127 }
1128 #ifdef VMS
1129 buf = slrn_strdup_printf ("%s\"%s\"", MAIL_PROTOCOL, to);
1130 vms_send_mail (buf, subject, file);
1131 slrn_free (buf);
1132 #else
1133
1134 while (1)
1135 {
1136 int rsp;
1137
1138 a = (Slrn_Article_Type*) slrn_malloc (sizeof(Slrn_Article_Type), 1, 1);
1139 if (a == NULL)
1140 return -1;
1141
1142 if (0 == (rsp = slrn_prepare_file_for_posting(file, &editline, a, to, 1)))
1143 break;
1144
1145 if (rsp == -1)
1146 {
1147 slrn_art_free_article(a);
1148 return -1;
1149 }
1150
1151 SLtt_beep ();
1152 if (rsp == 1)
1153 {
1154 /* Note to translators:
1155 * In the next two strings, "yY" is "yes", "eE" is "edit", "nN" is "no",
1156 * "cC" is "cancel" and "fF" means "force". The usual rules apply.
1157 */
1158 char *responses = _("yYeEnNcC");
1159 if (strlen (responses) != 8)
1160 responses = "";
1161 rsp = slrn_get_response ("yYEenNcC\007", responses, _("re-\001Edit, or \001Cancel"));
1162 }
1163 else
1164 {
1165 char *responses = _("yYeEnNcCfF");
1166 if (strlen (responses) != 10)
1167 responses = "";
1168 rsp = slrn_get_response ("EeyYnNcC\007Ff", responses, _("re-\001Edit, \001Cancel, or \001Force the mailing (not recommended)"));
1169 }
1170
1171 rsp = slrn_map_translated_char ("yYeEnNcCfF", _("yYeEnNcCfF"), rsp) | 0x20;
1172
1173 if ((rsp == 'c') || (rsp == 'n') ||(rsp == 7) )
1174 {
1175 slrn_art_free_article(a);
1176 return -1;
1177 }
1178 if (rsp == 'f')
1179 break;
1180
1181 if (slrn_edit_file (Slrn_Editor_Mail, file, editline, 1) < 0)
1182 {
1183 slrn_art_free_article(a);
1184 return -1;
1185 }
1186 /* try again */
1187 slrn_art_free_article (a);
1188 } /* while (1)*/
1189
1190 slrn_message_now (_("Sending ..."));
1191
1192 # if defined(IBMPC_SYSTEM)
1193 pp = slrn_open_tmpfile (outfile, sizeof (outfile));
1194 # else
1195 pp = slrn_popen (Slrn_SendMail_Command, "w");
1196 # endif
1197
1198 a->cline=a->lines;
1199 while (a->cline != NULL)
1200 {
1201 fputs (a->cline->buf, pp);
1202 putc('\n', pp);
1203 a->cline=a->cline->next;
1204 }
1205 # if defined(IBMPC_SYSTEM)
1206 slrn_fclose (pp);
1207 buf = slrn_strdup_strcat (Slrn_SendMail_Command, " ", outfile, NULL);
1208 /* FIXME */
1209 if (buf != NULL)
1210 {
1211 slrn_posix_system (buf, 0);
1212 slrn_free (buf);
1213 }
1214 # else
1215 slrn_pclose (pp);
1216 # endif
1217
1218 #endif /* NOT VMS */
1219 slrn_message (_("Sending...done"));
1220
1221 if (-1 == slrn_save_article_to_mail_file (a, Slrn_Save_Replies_File))
1222 {
1223 slrn_art_free_article(a);
1224 return -1;
1225 }
1226
1227 slrn_art_free_article(a);
1228 return 0;
1229 }
1230
1231 /*}}}*/
1232
1233 #if SLRN_HAS_PIPING
_slrn_pclose(FILE * fp)1234 int _slrn_pclose (FILE *fp)
1235 {
1236 int ret;
1237
1238 ret = pclose (fp);
1239 if (ret == 0) return ret;
1240
1241 #if defined(WIFEXITED) && defined(WEXITSTATUS)
1242 if ((ret != -1) && WIFEXITED(ret))
1243 {
1244 ret = WEXITSTATUS(ret);
1245 }
1246 #endif
1247 return ret;
1248 }
1249 #endif /* SLRN_HAS_PIPING */
1250
1251 #if SLRN_HAS_PIPING
1252 /* There appears to be no simply way of getting the command assocated with
1253 * a pipe file descriptor. Therefore, I will simply store them in a table.
1254 */
1255 typedef struct _Pipe_Cmd_Table_Type
1256 {
1257 char *cmd;
1258 FILE *fp;
1259 struct _Pipe_Cmd_Table_Type *next;
1260 }
1261 Pipe_Cmd_Table_Type;
1262
1263 Pipe_Cmd_Table_Type *Pipe_Cmd_Table;
1264
store_pipe_cmd(char * cmd,FILE * fp)1265 static int store_pipe_cmd (char *cmd, FILE *fp)
1266 {
1267 Pipe_Cmd_Table_Type *p;
1268
1269 if (NULL == (cmd = SLang_create_slstring (cmd)))
1270 return -1;
1271
1272 p = (Pipe_Cmd_Table_Type *)slrn_malloc (sizeof (Pipe_Cmd_Table_Type), 1, 0);
1273 if (p == NULL)
1274 {
1275 SLang_free_slstring (cmd);
1276 return -1;
1277 }
1278 p->cmd = cmd;
1279 p->fp = fp;
1280 p->next = Pipe_Cmd_Table;
1281 Pipe_Cmd_Table = p;
1282 return 0;
1283 }
1284
delete_pipe_cmd(FILE * fp)1285 static void delete_pipe_cmd (FILE *fp)
1286 {
1287 Pipe_Cmd_Table_Type *last, *next;
1288
1289 last = NULL;
1290 next = Pipe_Cmd_Table;
1291 while (next != NULL)
1292 {
1293 if (next->fp == fp)
1294 {
1295 if (last != NULL)
1296 last->next = next->next;
1297 else
1298 Pipe_Cmd_Table = next->next;
1299
1300 SLang_free_slstring (next->cmd);
1301 slrn_free ((char *) next);
1302 return;
1303 }
1304
1305 last = next;
1306 next = next->next;
1307 }
1308
1309 /* should not be reached */
1310 }
1311
get_pipe_cmd(FILE * fp)1312 static char *get_pipe_cmd (FILE *fp)
1313 {
1314 Pipe_Cmd_Table_Type *p;
1315
1316 p = Pipe_Cmd_Table;
1317 while (p != NULL)
1318 {
1319 if (p->fp == fp)
1320 return p->cmd;
1321
1322 p = p->next;
1323 }
1324
1325 return _("**UNKNOWN**");
1326 }
1327 #endif /* SLRN_HAS_PIPING */
slrn_pclose(FILE * fp)1328 int slrn_pclose (FILE *fp) /*{{{*/
1329 {
1330 #if SLRN_HAS_PIPING
1331 int ret;
1332 if (fp == NULL) return -1;
1333
1334 ret = _slrn_pclose (fp);
1335 if (ret)
1336 {
1337 char buf[SLRN_MAX_PATH_LEN];
1338 fprintf (stderr, _("Command %s returned exit status %d. Press RETURN.\n"),
1339 get_pipe_cmd (fp), ret);
1340 fgets (buf, sizeof(buf), stdin);
1341 }
1342
1343 delete_pipe_cmd (fp);
1344
1345 slrn_set_display_state (SLRN_TTY_INIT | SLRN_SMG_INIT);
1346 return 0;
1347 #else
1348 return -1;
1349 #endif
1350 }
1351
1352 /*}}}*/
1353
slrn_popen(char * cmd,char * mode)1354 FILE *slrn_popen (char *cmd, char *mode) /*{{{*/
1355 {
1356 #if SLRN_HAS_PIPING
1357 FILE *fp;
1358
1359 slrn_set_display_state (0);
1360 fp = popen (cmd, mode);
1361
1362 if (fp == NULL)
1363 {
1364 char buf[256];
1365 fprintf (stderr, _("Command %s failed to run. Press RETURN.\n"), cmd);
1366 fgets (buf, sizeof(buf), stdin);
1367 slrn_set_display_state (SLRN_TTY_INIT | SLRN_SMG_INIT);
1368 }
1369 else (void) store_pipe_cmd (cmd, fp);
1370
1371 return fp;
1372 #else
1373 return NULL;
1374 #endif
1375 }
1376
1377 /*}}}*/
1378
1379 /*}}}*/
1380
1381 /* returns a malloced string */
create_edit_command(char * edit,char * file,unsigned int line)1382 static char *create_edit_command (char *edit, char *file, unsigned int line) /*{{{*/
1383 {
1384 int d, s;
1385 char ch, *p = edit;
1386 /* Look for %d and %s */
1387
1388 d = s = 0;
1389
1390 while (0 != (ch = *p++))
1391 {
1392 if (ch != '%') continue;
1393 ch = *p;
1394 if (!d && (ch == 'd'))
1395 {
1396 *p = 'u'; /* map %d to %u (unsigned) */
1397 if (s == 0) d = 1; else d = 2;
1398 }
1399 else if (!s && (ch == 's'))
1400 {
1401 if (d == 0) s = 1; else s = 2;
1402 }
1403 else
1404 {
1405 slrn_error (_("Invalid Editor definition."));
1406 return NULL;
1407 }
1408 p++;
1409 }
1410
1411 #if defined(IBMPC_SYSTEM)
1412 /* Convert editor pathnames from / form to \\ form. I wonder what
1413 * happens when the pathname contains a space. Hmmm...
1414 */
1415 p = edit;
1416 while ((*p != ' ') && (*p != '\t') && (*p != 0))
1417 {
1418 if (*p == '/') *p = SLRN_PATH_SLASH_CHAR;
1419 p++;
1420 }
1421 #endif
1422
1423 /* No %d, %s */
1424
1425 if ((d == 0) && (s == 0))
1426 {
1427 return slrn_strdup_strcat (edit, " ", file, NULL);
1428 }
1429 else if (d == 0)
1430 {
1431 return slrn_strdup_printf (edit, file);
1432 }
1433 else if (s == 0)
1434 {
1435 char *retval, *cmd1;
1436 cmd1 = slrn_strdup_printf (edit, (int) line);
1437 retval = slrn_strdup_strcat (cmd1, " ", file, NULL);
1438 slrn_free (cmd1);
1439 return retval;
1440 }
1441 else /* d and s */
1442 {
1443 if (d == 1)
1444 return slrn_strdup_printf (edit, line, file);
1445 else return slrn_strdup_printf (edit, file, line);
1446 }
1447 /* We should never get here */
1448 return NULL;
1449 }
1450
1451 /*}}}*/
1452
1453 /* This function returns -1 upon failure, -2 upon unmodified edit */
slrn_edit_file(char * editor,char * file,unsigned int line,int check_mtime)1454 int slrn_edit_file (char *editor, char *file, unsigned int line,
1455 int check_mtime) /*{{{*/
1456 {
1457 char *cmd, *editcmd, *msg = NULL;
1458 int ret;
1459 unsigned long mtime = 0;
1460 struct stat st;
1461
1462 if (Slrn_Abort_Unmodified == 0)
1463 check_mtime = 0;
1464
1465 if ((editor == NULL) || (*editor == 0))
1466 editor = Slrn_Editor;
1467
1468 if (((editor == NULL) || (*editor == 0))
1469 && (NULL == (editor = getenv("SLRN_EDITOR")))
1470 && (NULL == (editor = getenv("SLANG_EDITOR")))
1471 && (NULL == (editor = getenv("EDITOR")))
1472 && (NULL == (editor = getenv("VISUAL"))))
1473 {
1474 #if defined(VMS) || defined(__NT__) || defined(__WIN32__)
1475 editor = "edit";
1476 #else
1477 # if defined(__os2__)
1478 editor = "e";
1479 # else
1480 # ifdef __unix__
1481 editor = "vi";
1482 # else
1483 slrn_error (_("No editor command defined."));
1484 return -1;
1485 # endif
1486 # endif
1487 #endif
1488 }
1489 editcmd = slrn_safe_strmalloc (editor);
1490
1491 if (NULL == (cmd = create_edit_command (editcmd, file, line))) return -1;
1492
1493 if (check_mtime
1494 && (0 == stat (file, &st)))
1495 mtime = (unsigned long) st.st_mtime;
1496
1497 ret = slrn_posix_system (cmd, 1);
1498
1499 #if defined(WIFEXITED) && defined(WEXITSTATUS)
1500 if ((ret != -1) && WIFEXITED(ret))
1501 {
1502 ret = WEXITSTATUS(ret);
1503 if (ret == 127)
1504 {
1505 msg = _("The editor could not be found.");
1506 ret = -1;
1507 }
1508 else if (ret == 126)
1509 {
1510 msg = _("The editor was found, but could not be executed.");
1511 ret = -1;
1512 }
1513 else if (ret)
1514 msg = _("The editor returned a non-zero status.");
1515 }
1516 #endif
1517
1518 /* Am I the only one who thinks this is a good idea?? */
1519 if (Slrn_TT_Initialized) while (SLang_input_pending (5))
1520 SLang_flush_input ();
1521
1522 if (check_mtime
1523 && (ret != -1)
1524 && (0 == stat (file, &st))
1525 && (mtime == (unsigned long) st.st_mtime))
1526 {
1527 if (msg == NULL)
1528 msg = _("File was not modified.");
1529 ret = -2;
1530 }
1531
1532 #if defined(IBMPC_SYSTEM) && !defined(__CYGWIN__)
1533 if ((strlen (cmd) > 1)
1534 && (cmd[1] == ':')
1535 && (cmd[2] != '\\'))
1536 {
1537 msg = _("Please use double '\\\\' to separate directories in editor_command");
1538 }
1539 #endif
1540
1541 if (msg != NULL)
1542 {
1543 slrn_message ("%s", msg);
1544 if (ret >= 0)
1545 {
1546 slrn_update_screen ();
1547 slrn_sleep (2);
1548 }
1549 }
1550 slrn_free (cmd);
1551 slrn_free (editcmd);
1552 return ret;
1553 }
1554
1555 /*}}}*/
1556
1557 /*{{{ Get Input From User Related Functions */
1558
rline_update(SLrline_Type * rli,char * prompt,char * buf,unsigned int len,unsigned int point,VOID_STAR client_data)1559 static void rline_update (SLrline_Type *rli, char *prompt,
1560 char *buf, unsigned int len, unsigned int point,
1561 VOID_STAR client_data)
1562 {
1563 int col;
1564 char *ubuf, *u, *umax, *upoint;
1565 unsigned int prompt_len;
1566
1567 (void) client_data;
1568 (void) rli;
1569
1570 slrn_push_suspension (0);
1571 if (prompt == NULL)
1572 prompt = "";
1573
1574 prompt_len = strlen (prompt);
1575 ubuf = slrn_safe_malloc (prompt_len + len + 1);
1576 strcpy (ubuf, prompt);
1577 strncpy (ubuf + prompt_len, buf, len);
1578
1579 len += prompt_len;
1580 ubuf[len] = 0;
1581
1582 umax = ubuf + len;
1583 upoint = ubuf + prompt_len + point;
1584
1585 u = ubuf;
1586 do
1587 {
1588 SLsmg_gotorc (SLtt_Screen_Rows - 1, 0);
1589 SLsmg_write_nchars (u, (unsigned int) (upoint - u));
1590 col = SLsmg_get_column ();
1591 if (col < SLtt_Screen_Cols)
1592 break;
1593
1594 u = skip_char (u, upoint, 1);
1595 }
1596 while (u < upoint);
1597
1598 SLsmg_write_nchars (upoint, (unsigned int) (umax-upoint));
1599 slrn_free (ubuf);
1600
1601 SLsmg_erase_eol ();
1602 SLsmg_gotorc (SLtt_Screen_Rows - 1, col);
1603 slrn_smg_refresh ();
1604 slrn_pop_suspension ();
1605 }
1606
1607 /* If 1, redraw read_line. If 2, redraw message */
1608 static int Reading_Input;
1609
redraw_mini_buffer(void)1610 static void redraw_mini_buffer (void) /*{{{*/
1611 {
1612 if (Reading_Input == 1)
1613 SLrline_redraw (Slrn_Keymap_RLI);
1614 else if (Reading_Input == 2)
1615 redraw_message ();
1616 }
1617
1618 /*}}}*/
1619
init_readline(void)1620 static SLang_RLine_Info_Type *init_readline (void) /*{{{*/
1621 {
1622 SLrline_Type *rli;
1623 unsigned int flags = SL_RLINE_BLINK_MATCH;
1624
1625 if (Slrn_UTF8_Mode)
1626 flags |= SL_RLINE_UTF8_MODE;
1627
1628 if (NULL == (rli = SLrline_open (SLtt_Screen_Cols, flags)))
1629 return NULL;
1630
1631 (void) SLrline_set_update_hook (rli, rline_update, NULL);
1632 return rli;
1633 }
1634
1635 /*}}}*/
1636
read_from_input_string(char * str)1637 static int read_from_input_string (char *str)
1638 {
1639 char *s;
1640
1641 if (Input_String == NULL) return -1;
1642
1643 s = slrn_strbyte (Input_String_Ptr, '\n');
1644 if (s != NULL)
1645 *s = 0;
1646
1647 strncpy (str, Input_String_Ptr, 255);
1648 str[255] = 0;
1649
1650 if (s == NULL)
1651 {
1652 SLFREE (Input_String);
1653 Input_String_Ptr = Input_String = NULL;
1654 }
1655 else Input_String_Ptr = s + 1;
1656
1657 return strlen (str);
1658 }
1659
1660 /* s could be NULL. If so, input string is cleared. The calling routine
1661 * should not free the input pointer.
1662 */
slrn_set_input_string(char * s)1663 void slrn_set_input_string (char *s)
1664 {
1665 slrn_free (Input_String);
1666 Input_String = s;
1667 Input_String_Ptr = s;
1668 }
1669
read_from_input_char(void)1670 static char read_from_input_char (void)
1671 {
1672 if (Input_Chars_Ptr == NULL)
1673 return 0;
1674
1675 if (*Input_Chars_Ptr == 0)
1676 {
1677 slrn_set_input_chars (NULL);
1678 return 0;
1679 }
1680
1681 return *Input_Chars_Ptr++;
1682 }
1683
slrn_set_input_chars(char * s)1684 void slrn_set_input_chars (char *s)
1685 {
1686 slrn_free (Input_Chars);
1687 Input_Chars = s;
1688 Input_Chars_Ptr = s;
1689 }
1690
1691 /* The char * argument is expected to be SLRN_MAX_PATH_LEN in size */
1692 static int (*Complete_Open) (char *);
1693 static int (*Complete_Next) (char *);
1694
1695 static char File_Pattern[SLRN_MAX_PATH_LEN], Dir_Name[SLRN_MAX_PATH_LEN];
1696 static Slrn_Dir_Type *Dir;
1697 static int In_Completion;
1698
1699 /* buf needs room for at least SLRN_MAX_PATH_LEN chars */
dir_findnext(char * buf)1700 static int dir_findnext (char *buf) /*{{{*/
1701 {
1702 Slrn_Dirent_Type *dirent;
1703 unsigned int len = strlen (File_Pattern);
1704
1705 while (NULL != (dirent = slrn_read_dir (Dir)))
1706 {
1707 char *name = dirent->name;
1708 if ((*name == '.') && ((*(name+1) == 0) ||
1709 ((*(name+1) == '.') && (*(name+2) == 0))))
1710 continue;
1711 if (!strncmp (dirent->name, File_Pattern, len))
1712 {
1713 strcpy (buf, Dir_Name); /* safe */
1714 len = strlen (buf);
1715 slrn_strncpy (buf+len, dirent->name, SLRN_MAX_PATH_LEN - len - 1);
1716 return 1;
1717 }
1718 }
1719 return 0;
1720 }
1721 /*}}}*/
1722
dir_findfirst(char * buf)1723 static int dir_findfirst (char *buf) /*{{{*/
1724 {
1725 int pos = strlen (buf);
1726
1727 if (Dir != NULL)
1728 {
1729 slrn_close_dir (Dir);
1730 Dir = NULL;
1731 }
1732
1733 while ((pos >= 0) && (buf[pos] != SLRN_PATH_SLASH_CHAR))
1734 pos--;
1735
1736 if (pos == -1)
1737 {
1738 unsigned int len;
1739 if (NULL == slrn_getcwd (Dir_Name, sizeof (Dir_Name) - 1))
1740 return 0;
1741 len = strlen (Dir_Name);
1742 Dir_Name[len] = SLRN_PATH_SLASH_CHAR;
1743 Dir_Name[len+1] = '\0';
1744 }
1745 else
1746 {
1747 if (pos + 2 > SLRN_MAX_PATH_LEN)
1748 pos = SLRN_MAX_PATH_LEN - 2;
1749 slrn_strncpy (Dir_Name, buf, pos + 2);
1750 }
1751
1752 pos++;
1753 slrn_strncpy (File_Pattern, buf + pos, sizeof (File_Pattern));
1754
1755 if (NULL == (Dir = slrn_open_dir (Dir_Name)))
1756 return 0;
1757
1758 return dir_findnext (buf);
1759 }
1760 /*}}}*/
1761
1762 typedef struct
1763 {
1764 char *what;
1765 void *dummy;
1766 }
1767 Generic_Var_Type;
1768
1769 static Generic_Var_Type *Var;
1770 static int Var_Pos;
1771
var_findnext(char * buf)1772 static int var_findnext (char *buf) /*{{{*/
1773 {
1774 unsigned int len = strlen (File_Pattern);
1775
1776 while (Var->what != NULL)
1777 {
1778 int retval = 0;
1779 if (!strncmp (Var->what, File_Pattern, len))
1780 {
1781 strcpy (buf, Dir_Name); /* safe */
1782 len = strlen (buf);
1783 slrn_strncpy (buf+len, Var->what, SLRN_MAX_PATH_LEN - len - 1);
1784 retval = 1;
1785 }
1786 Var++;
1787 if ((Var->what == NULL) && (Var_Pos == 0))
1788 {
1789 Var = (Generic_Var_Type*) Slrn_Str_Variables;
1790 Var_Pos++;
1791 }
1792 if (retval) return 1;
1793 }
1794 return 0;
1795 }
1796 /*}}}*/
1797
var_findfirst(char * buf)1798 static int var_findfirst (char *buf) /*{{{*/
1799 {
1800 int pos = strlen (buf);
1801 while ((pos > 0) && (buf[pos-1] != ' '))
1802 pos--;
1803
1804 slrn_strncpy (Dir_Name, buf, pos + 1);
1805 slrn_strncpy (File_Pattern, buf + pos, SLRN_MAX_PATH_LEN);
1806 Var = (Generic_Var_Type*) Slrn_Int_Variables; Var_Pos = 0;
1807 return var_findnext (buf);
1808 }
1809 /*}}}*/
1810
strpcmp(char ** a,char ** b)1811 static int strpcmp (char **a, char **b)
1812 {
1813 return strcmp (*a, *b);
1814 }
1815
rli_self_insert(void)1816 static void rli_self_insert (void) /*{{{*/
1817 {
1818 char last_char [2];
1819 last_char[0] = (char) SLang_Last_Key_Char;
1820 last_char[1] = '\0';
1821 (void) SLrline_ins (Slrn_Keymap_RLI, last_char, 1);
1822 /* SLrline_redraw in slang-2.0.x did not use the redraw-hook. So
1823 * avoid using this here. It is not needed anyway.
1824 */
1825 /* SLrline_redraw (Slrn_Keymap_RLI); */
1826 }
1827 /*}}}*/
1828
generic_mini_complete(int cycle)1829 static void generic_mini_complete (int cycle) /*{{{*/
1830 {
1831 char *pl, *pb;
1832 char last[SLRN_MAX_PATH_LEN], buf[SLRN_MAX_PATH_LEN];
1833 static char prev[SLRN_MAX_PATH_LEN], prevcall[SLRN_MAX_PATH_LEN];
1834 int repeat = 1; /* whether we are called with identical values again */
1835 unsigned int n;
1836 static int flag = 0; /* when flag goes 0, we call open */
1837 static unsigned int lastpoint = 0;
1838 char **argv = NULL;
1839 unsigned int argc = 0, maxargc = 0;
1840 unsigned int point;
1841 char *rli_buf;
1842
1843 if (Complete_Open == NULL)
1844 {
1845 rli_self_insert ();
1846 return;
1847 }
1848
1849 n = sizeof (buf);
1850 (void) SLrline_get_point (Slrn_Keymap_RLI, &point);
1851 if (point < n)
1852 n = point + 1;
1853
1854 rli_buf = SLrline_get_line (Slrn_Keymap_RLI); /* malloced pointer */
1855 if (rli_buf == NULL)
1856 return;
1857
1858 slrn_strncpy (buf, rli_buf, n);
1859 n = 0;
1860
1861 if (strcmp (rli_buf, prevcall) ||
1862 (point != lastpoint) ||
1863 (0 == In_Completion))
1864 {
1865 slrn_strncpy (prev, buf, sizeof(prev));
1866 /* strcpy (prev, buf); */ /* safe */ /* save this search context */
1867 flag = 0;
1868 repeat = 0;
1869 }
1870
1871 SLfree (rli_buf); rli_buf = NULL;
1872
1873 if (In_Completion == 2)
1874 repeat = 0;
1875
1876 if (cycle)
1877 {
1878 if (flag)
1879 flag = (*Complete_Next)(buf);
1880 else if (0 == (flag = (*Complete_Open)(buf)))
1881 {
1882 rli_self_insert ();
1883 return;
1884 }
1885 if (flag == 0)
1886 slrn_strncpy (buf, prev, sizeof (buf));
1887 strcpy (last, buf); /* safe */
1888 }
1889 else
1890 {
1891 flag = (*Complete_Open)(buf);
1892 strcpy (last, buf); /* safe */
1893
1894 /* This loop tests all values from complete_next and returns the
1895 * smallest length match of initial characters of buf */
1896 while (flag)
1897 {
1898 pl = last;
1899 pb = buf;
1900
1901 if (repeat)
1902 {
1903 if (argc == maxargc)
1904 {
1905 char **newargv;
1906 maxargc += 512;
1907 newargv = (char **) slrn_realloc
1908 ((char *) argv, maxargc * sizeof (char *), 0);
1909 if (newargv == NULL)
1910 {
1911 slrn_free_argc_argv_list (argc, argv);
1912 slrn_free ((char *) argv);
1913 argc = 0;
1914 }
1915 argv = newargv;
1916 }
1917 if ((NULL != argv) &&
1918 (NULL != (argv[argc] = slrn_safe_strmalloc (buf))))
1919 argc++;
1920 }
1921
1922 while (*pl && (*pl == *pb))
1923 {
1924 pl++;
1925 pb++;
1926 }
1927
1928 *pl = 0;
1929 n++;
1930 flag = (*Complete_Next)(buf);
1931 }
1932 }
1933
1934 if (cycle || n)
1935 {
1936 unsigned int len;
1937
1938 if (repeat && (argc > 1))
1939 {
1940 int sel;
1941 void (*qsort_fun) (char **, unsigned int,
1942 unsigned int, int (*)(char **, char **));
1943 /* This seems to be necessary (see art_sort.c:slrn_sort_headers) */
1944 qsort_fun = (void (*)(char **, unsigned int,
1945 unsigned int, int (*)(char **, char **)))
1946 qsort;
1947
1948 qsort_fun (argv, argc, sizeof (char *), strpcmp);
1949
1950 sel = slrn_select_list_mode (_("Possible completions"), argc,
1951 argv, 0, 1, NULL);
1952 slrn_update_screen ();
1953 if (sel != -1)
1954 {
1955 slrn_strncpy (last, argv[sel], sizeof (last));
1956 n = 1;
1957 }
1958 }
1959
1960 len = strlen (last);
1961
1962 if ((n < 2) && ((FVOID_STAR) Complete_Open == (FVOID_STAR) dir_findfirst) &&
1963 (flag || !cycle) && (len + 1 < sizeof (last)))
1964 {
1965 if (2 == slrn_file_exists (last))
1966 {
1967 last[len] = SLRN_PATH_SLASH_CHAR;
1968 last[len+1] = 0;
1969 }
1970 }
1971
1972 if (-1 == SLrline_set_line (Slrn_Keymap_RLI, last))
1973 return;
1974
1975 SLrline_redraw (Slrn_Keymap_RLI);
1976 }
1977 else SLtt_beep();
1978
1979 if (!cycle)
1980 strcpy (prev, last); /* safe; make this the new search context */
1981
1982 slrn_free_argc_argv_list (argc, argv);
1983 slrn_free ((char *) argv);
1984 rli_buf = SLrline_get_line (Slrn_Keymap_RLI);
1985 if (rli_buf == NULL)
1986 {
1987 In_Completion = 0;
1988 return;
1989 }
1990 slrn_strncpy (prevcall, rli_buf, sizeof (prevcall));
1991 SLfree (rli_buf);
1992 (void) SLrline_get_point (Slrn_Keymap_RLI, &lastpoint);
1993 In_Completion = cycle ? 2 : 1;
1994
1995 return;
1996 }
1997
1998 /*}}}*/
1999
mini_complete(SLrline_Type * rli)2000 static int mini_complete (SLrline_Type *rli)
2001 {
2002 (void) rli;
2003 generic_mini_complete (0);
2004 return 0;
2005 }
2006
mini_cycle(SLrline_Type * rli)2007 static int mini_cycle (SLrline_Type *rli)
2008 {
2009 (void) rli;
2010 generic_mini_complete (1);
2011 return 0;
2012 }
2013
rli_del_bol(SLrline_Type * rli)2014 static int rli_del_bol (SLrline_Type *rli) /*{{{*/
2015 {
2016 unsigned int point;
2017
2018 (void) SLrline_get_point (rli, &point);
2019 (void) SLrline_set_point (rli, 0);
2020 (void) SLrline_del (rli, point);
2021 return 0;
2022 }
2023 /*}}}*/
2024
rli_del_bow(SLrline_Type * rli)2025 static int rli_del_bow (SLrline_Type *rli) /*{{{*/
2026 {
2027 char *buf, *b;
2028 unsigned int point;
2029 unsigned int len;
2030
2031 (void) SLrline_get_point (rli, &point);
2032 if (point == 0)
2033 return 0;
2034
2035 if (NULL == (buf = SLrline_get_line (rli)))
2036 return -1;
2037
2038 b = buf + (point - 1);
2039 while ((b > buf) && ((*b == ' ') || (*b == '\t')))
2040 b--;
2041
2042 while (b > buf)
2043 {
2044 if ((*b == ' ') || (*b == '\t'))
2045 {
2046 b++;
2047 break;
2048 }
2049 b--;
2050 }
2051
2052 len = point;
2053 point = b - buf;
2054 (void) SLrline_set_point (rli, point);
2055 (void) SLrline_del (rli, len - point);
2056
2057 SLfree (buf);
2058 return 0;
2059 }
2060 /*}}}*/
2061
2062 #define A_KEY(s, f) {s, (int (*)(void)) f}
2063
2064 static SLKeymap_Function_Type Slrn_Custom_Readline_Functions [] =
2065 {
2066 A_KEY("complete", mini_complete),
2067 A_KEY("cycle", mini_cycle),
2068 A_KEY("delbol", rli_del_bol),
2069 A_KEY("delbow", rli_del_bow),
2070 A_KEY(NULL, NULL)
2071 };
2072
slrn_rline_setkey(char * key,char * fun,SLkeymap_Type * kmap)2073 int slrn_rline_setkey (char *key, char *fun, SLkeymap_Type *kmap)
2074 {
2075 SLKeymap_Function_Type *tmp;
2076 int failure;
2077
2078 if (NULL != SLang_find_key_function(fun, kmap))
2079 return SLang_define_key (key, fun, kmap);
2080
2081 tmp = kmap->functions;
2082 kmap->functions = Slrn_Custom_Readline_Functions;
2083 failure = SLang_define_key (key, fun, kmap);
2084 kmap->functions = tmp;
2085
2086 return failure;
2087 }
2088
2089 /* str needs to have enough space for SLRL_DISPLAY_BUFFER_SIZE characters */
generic_read_input(char * prompt,char * dfl,char * str,int trim_flag,int no_echo,int point)2090 static int generic_read_input (char *prompt, char *dfl, char *str, int trim_flag,
2091 int no_echo, int point) /*{{{*/
2092 {
2093 int i;
2094 int tt_init_state;
2095 char prompt_buf[SLRL_DISPLAY_BUFFER_SIZE];
2096 char *buf;
2097 unsigned int len;
2098 int save_slang_error;
2099
2100 if (prompt == NULL) prompt = "";
2101
2102 Slrn_Full_Screen_Update = 1;
2103
2104 slrn_strncpy (prompt_buf, prompt, sizeof (prompt_buf));
2105 len = strlen (prompt);
2106
2107 if ((dfl != NULL) && *dfl)
2108 {
2109 if (slrn_snprintf (prompt_buf + len, sizeof (prompt_buf) - len,
2110 _("(default: %s) "), dfl) == (int) (sizeof (prompt_buf) - len))
2111 {
2112 *(prompt_buf + len) = '\0';
2113 dfl = NULL;
2114 }
2115 }
2116 prompt = prompt_buf;
2117
2118 if ((str == NULL) && (dfl == NULL)) return -1;
2119
2120 SLrline_set_display_width (Slrn_Keymap_RLI, SLtt_Screen_Cols);
2121
2122 /* slrn_set_suspension (1); */
2123
2124 if ((str != NULL) && *str)
2125 {
2126 if (-1 == SLrline_set_line (Slrn_Keymap_RLI, str))
2127 return -1;
2128
2129 if (point < 0)
2130 {
2131 unsigned int slen = strlen (str);
2132 if ((unsigned int)-point > slen) point = 0;
2133 else point = slen + (1 + point);
2134 }
2135 SLrline_set_point (Slrn_Keymap_RLI, point);
2136 *str = 0;
2137 }
2138 if (str == NULL) str = dfl;
2139
2140 i = read_from_input_string (str);
2141 if (i >= 0) return i;
2142
2143 tt_init_state = Slrn_TT_Initialized;
2144
2145 slrn_set_display_state (Slrn_TT_Initialized | SLRN_TTY_INIT);
2146
2147 if (no_echo)
2148 SLrline_set_echo (Slrn_Keymap_RLI, 0);
2149 else
2150 SLrline_set_echo (Slrn_Keymap_RLI, 1);
2151
2152 if (tt_init_state & SLRN_SMG_INIT)
2153 (void) SLrline_set_update_hook (Slrn_Keymap_RLI, rline_update, NULL);
2154 else
2155 (void) SLrline_set_update_hook (Slrn_Keymap_RLI, NULL, NULL);
2156
2157 slrn_enable_mouse (0);
2158
2159 save_slang_error = SLang_get_error ();
2160 SLang_set_error (0);
2161
2162 Reading_Input = 1;
2163 slrn_set_color (MESSAGE_COLOR);
2164
2165 buf = SLrline_read_line (Slrn_Keymap_RLI, prompt, &len);
2166 slrn_set_color (0);
2167 Reading_Input = 0;
2168
2169 slrn_enable_mouse (1);
2170
2171 if ((buf != NULL) && (0 == SLang_get_error ()) && !SLKeyBoard_Quit)
2172 {
2173 char *b = buf;
2174
2175 if (*b)
2176 {
2177 if (no_echo == 0) SLrline_save_line (Slrn_Keymap_RLI);
2178 if (trim_flag)
2179 {
2180 slrn_trim_string (b);
2181 b = slrn_skip_whitespace (b);
2182 }
2183 }
2184 else if (dfl != NULL) b = dfl;
2185
2186 /* b could be equal to dfl and dfl could be equal to str. If this is
2187 * the case, there is no need to perform the strcpy */
2188 if (b != str)
2189 slrn_strncpy (str, b, SLRL_DISPLAY_BUFFER_SIZE); /* safe */
2190
2191 i = strlen (str);
2192 }
2193 else i = -1;
2194
2195 SLfree (buf);
2196
2197 if (SLKeyBoard_Quit) i = -1;
2198 SLKeyBoard_Quit = 0;
2199 SLang_set_error (save_slang_error);
2200
2201 slrn_set_display_state (tt_init_state);
2202
2203 if (tt_init_state & SLRN_SMG_INIT)
2204 {
2205 /* put cursor at edge of screen to comfort user */
2206 SLsmg_gotorc (SLtt_Screen_Rows - 1, 0);
2207 slrn_smg_refresh ();
2208 }
2209 else
2210 {
2211 putc ('\n', stdout);
2212 fflush (stdout);
2213 }
2214
2215 /* slrn_set_suspension (0); */
2216 return i;
2217 }
2218
2219 /*}}}*/
2220
slrn_read_input(char * prompt,char * dfl,char * str,int trim_flag,int point)2221 int slrn_read_input (char *prompt, char *dfl, char *str, int trim_flag, int point)
2222 {
2223 return generic_read_input (prompt, dfl, str, trim_flag, 0, point);
2224 }
2225
slrn_read_input_no_echo(char * prompt,char * dfl,char * str,int trim_flag,int point)2226 int slrn_read_input_no_echo (char *prompt, char *dfl, char *str, int trim_flag, int point)
2227 {
2228 return generic_read_input (prompt, dfl, str, trim_flag, 1, point);
2229 }
2230
slrn_read_filename(char * prompt,char * dfl,char * str,int trim_flag,int point)2231 int slrn_read_filename (char *prompt, char *dfl, char *str, int trim_flag, int point)
2232 {
2233 int retval;
2234 Complete_Open = dir_findfirst;
2235 Complete_Next = dir_findnext;
2236 retval = generic_read_input (prompt, dfl, str, trim_flag, 0, point);
2237 Complete_Open = NULL;
2238 Complete_Next = NULL;
2239 In_Completion = 0;
2240 return retval;
2241 }
2242
slrn_read_variable(char * prompt,char * dfl,char * str,int trim_flag,int point)2243 int slrn_read_variable (char *prompt, char *dfl, char *str, int trim_flag, int point)
2244 {
2245 int retval;
2246 Complete_Open = var_findfirst;
2247 Complete_Next = var_findnext;
2248 retval = generic_read_input (prompt, dfl, str, trim_flag, 0, point);
2249 Complete_Open = NULL;
2250 Complete_Next = NULL;
2251 In_Completion = 0;
2252 return retval;
2253 }
2254
slrn_read_artnum_int(char * prompt,NNTP_Artnum_Type * dflt,NNTP_Artnum_Type * np)2255 int slrn_read_artnum_int (char *prompt, NNTP_Artnum_Type *dflt, NNTP_Artnum_Type *np) /*{{{*/
2256 {
2257 char sdfl_buf[256];
2258 char *sdfl = NULL;
2259 char str[SLRL_DISPLAY_BUFFER_SIZE];
2260 NNTP_Artnum_Type n;
2261
2262 if (dflt != NULL)
2263 {
2264 sprintf (sdfl_buf, NNTP_FMT_ARTNUM, *dflt); /* safe */
2265 sdfl = sdfl_buf;
2266 }
2267
2268 *str = 0;
2269 if (-1 == slrn_read_input (prompt, sdfl, str, 1, 0))
2270 {
2271 slrn_error (_("Abort!"));
2272 return -1;
2273 }
2274
2275 if (1 != sscanf(str, NNTP_FMT_ARTNUM, &n))
2276 {
2277 slrn_error (_("Integer expected."));
2278 return -1;
2279 }
2280 *np = n;
2281 return 0;
2282 }
2283
2284 /*}}}*/
2285
slrn_init_readline(void)2286 int slrn_init_readline (void) /*{{{*/
2287 {
2288 if ((Slrn_Keymap_RLI == NULL)
2289 && (NULL == (Slrn_Keymap_RLI = init_readline ())))
2290 return -1;
2291
2292 Slrn_RLine_Keymap = SLrline_get_keymap (Slrn_Keymap_RLI);
2293 SLkm_define_key ("\t", (FVOID_STAR) mini_complete, Slrn_RLine_Keymap);
2294 SLkm_define_key (" ", (FVOID_STAR) mini_cycle, Slrn_RLine_Keymap);
2295 SLkm_define_key ("^U", (FVOID_STAR) rli_del_bol, Slrn_RLine_Keymap);
2296 SLkm_define_key ("^W", (FVOID_STAR) rli_del_bow, Slrn_RLine_Keymap);
2297
2298 return 0;
2299 }
2300
2301 /*}}}*/
2302
slrn_map_translated_char(char * native_chars,char * translated_chars,char rsp)2303 char slrn_map_translated_char (char *native_chars, /*{{{*/
2304 char *translated_chars, char rsp)
2305 {
2306 char *pos;
2307 if ((strlen (native_chars) != strlen (translated_chars)) ||
2308 (NULL != slrn_strbyte (native_chars, rsp)) ||
2309 (NULL == (pos = slrn_strbyte (translated_chars, rsp))))
2310 return rsp;
2311 return native_chars[pos - translated_chars];
2312 }
2313 /*}}}*/
2314
slrn_get_response(char * valid_chars,char * translated_chars,char * str,...)2315 char slrn_get_response (char *valid_chars, char *translated_chars, /*{{{*/
2316 char *str, ...)
2317 {
2318 char ch;
2319 va_list ap;
2320 char *v;
2321
2322 /* if (SLang_Error) return -1; */
2323 if (Error_Present)
2324 slrn_error_now (2, NULL);
2325
2326 while (1)
2327 {
2328 Slrn_Full_Screen_Update = 1;
2329
2330 ch = read_from_input_char ();
2331
2332 if (ch == 0)
2333 {
2334 if (Slrn_TT_Initialized == 0)
2335 {
2336 char buf[256];
2337
2338 va_start(ap, str);
2339 slrn_tty_vmessage (stdout, str, ap);
2340 va_end(ap);
2341
2342 *buf = 0;
2343 (void) fgets (buf, sizeof(buf), stdin);
2344 ch = *buf;
2345 }
2346 else
2347 {
2348 SLang_flush_input ();
2349 slrn_clear_message ();
2350
2351 va_start(ap, str);
2352 vmessage_1 (MESSAGE_COLOR, str, ap);
2353 va_end(ap);
2354
2355 slrn_smg_refresh ();
2356
2357 Reading_Input = 2;
2358 ch = SLang_getkey ();
2359 Reading_Input = 0;
2360
2361 slrn_clear_message ();
2362 SLang_set_error (0);
2363 SLKeyBoard_Quit = 0;
2364 }
2365 }
2366
2367 v = valid_chars;
2368 while (*v)
2369 {
2370 if (*v == ch) return ch;
2371 v++;
2372 }
2373 v = translated_chars;
2374 while (*v)
2375 {
2376 if (*v == ch) return ch;
2377 v++;
2378 }
2379
2380 slrn_error_now (0, _("Invalid response! Try again."));
2381 if (Slrn_TT_Initialized & SLRN_TTY_INIT)
2382 {
2383 (void) SLang_input_pending (15);
2384 }
2385 }
2386 }
2387
2388 /*}}}*/
2389
2390 /*{{{ Doubles percent characters. p0 is source, p is destination. */
escape_percent_chars(char * p,char * p0,char * pmax)2391 static void escape_percent_chars (char *p, char *p0, char *pmax)
2392 {
2393 while ((*p0) && (p < pmax - 2))
2394 {
2395 if (*p0 == '%')
2396 *p++ = '%';
2397 *p++ = *p0++;
2398 }
2399 *p = '\0';
2400 }
2401 /*}}}*/
2402
slrn_get_yesno(int dflt,char * str,...)2403 int slrn_get_yesno (int dflt, char *str, ...) /*{{{*/
2404 /* For both dflt and the return value, 0 means "no", 1 is "yes". */
2405 {
2406 va_list ap;
2407 char buf0[512], buf[512];
2408 char ch, rsp;
2409 char *prompt, *fmt;
2410 /* Note to translators:
2411 * The translated string needs to have exactly four characters.
2412 * The first two become valid keys for "yes", the last two for "no".
2413 * You *cannot* use "y" for "no" or "n" for "yes".
2414 */
2415 char *responses=_("yYnN");
2416
2417 /* if (SLang_Error) return -1; */
2418
2419 va_start(ap, str);
2420 (void) slrn_vsnprintf(buf0, sizeof (buf0), str, ap);
2421 va_end(ap);
2422
2423 /* As the prompt will be processed through printf again (by
2424 * slrn_get_response), we need to escape percent characters. */
2425 escape_percent_chars (buf, buf0, buf + sizeof (buf));
2426
2427 if (dflt)
2428 {
2429 ch = 'y';
2430 fmt = _("? [\001Y]es, \001No");
2431 }
2432 else
2433 {
2434 ch = 'n';
2435 fmt = _("? \001Yes, [\001N]o");
2436 }
2437
2438 prompt = slrn_strdup_strcat (buf, fmt, NULL);
2439 if (strlen (responses) != 4) /* Translator messed it up */
2440 responses = "";
2441 rsp = slrn_get_response ("yYnN\r\n", responses, "%s", prompt);
2442 slrn_free (prompt);
2443 if ((rsp == '\r') || (rsp == '\n')) rsp = ch;
2444 else rsp = slrn_map_translated_char ("yYnN", responses, rsp) | 0x20;
2445
2446 if (rsp == 'n')
2447 return 0;
2448 return 1;
2449 }
2450
2451 /*}}}*/
slrn_get_yesno_cancel(int dflt,char * str,...)2452 int slrn_get_yesno_cancel (int dflt, char *str, ...) /*{{{*/
2453 {
2454 va_list ap;
2455 char buf[512];
2456 char rsp, *prompt;
2457 /* Note to translators:
2458 * The translated string needs to have exactly six characters.
2459 * The first two become valid keys for "yes", the next two for "no",
2460 * the last ones for "cancel". You cannot use the default characters
2461 * for other fields than they originally stood for.
2462 */
2463 char *responses=_("yYnNcC");
2464 if (strlen (responses) != 6)
2465 responses = "";
2466
2467 if (SLang_get_error ()) return -1;
2468
2469 va_start(ap, str);
2470 (void) slrn_vsnprintf(buf, sizeof(buf), str, ap);
2471 va_end(ap);
2472
2473 if (dflt == 1)
2474 prompt = slrn_strdup_strcat (buf, _("? [\001Y]es, \001No, \001Cancel"), NULL);
2475 else if (dflt == 0)
2476 prompt = slrn_strdup_strcat (buf, _("? Yes, \001[N]o, \001Cancel"), NULL);
2477 else
2478 prompt = slrn_strdup_strcat (buf, _("? Yes, \001No, \001[C]ancel"), NULL);
2479
2480 if (prompt == NULL)
2481 return -1;
2482
2483 rsp = slrn_get_response ("\007yYnNcC\r", responses, "%s", prompt);
2484 slrn_free (prompt);
2485
2486 if (rsp == '\r') return dflt;
2487
2488 if (rsp == 7) return -1;
2489
2490 rsp = slrn_map_translated_char ("yYnNcC", responses, rsp) | 0x20;
2491
2492 if (rsp == 'y') return 1;
2493 if (rsp == 'n') return 0;
2494 return -1;
2495 }
2496
2497 /*}}}*/
2498
slrn_get_mouse_rc(int * rp,int * cp)2499 void slrn_get_mouse_rc (int *rp, int *cp) /*{{{*/
2500 {
2501 int r, c;
2502
2503 c = (unsigned char) SLang_getkey () - 32;
2504 r = (unsigned char) SLang_getkey () - 32;
2505 if (cp != NULL) *cp = c;
2506 if (rp != NULL) *rp = r;
2507 }
2508
2509 /*}}}*/
2510
slrn_evaluate_cmd(void)2511 void slrn_evaluate_cmd (void) /*{{{*/
2512 {
2513 char buf[SLRL_DISPLAY_BUFFER_SIZE];
2514
2515 *buf = '\0';
2516 if (slrn_read_input ("S-Lang> ", NULL, buf, 0, 0) > 0)
2517 {
2518 SLang_load_string (buf);
2519 }
2520
2521 SLang_set_error (0);
2522 }
2523 /*}}}*/
2524
2525 /*}}}*/
2526
2527 /*{{{ Misc Regexp Utility Functions */
2528
slrn_compile_regexp_pattern(char * pat)2529 SLRegexp_Type *slrn_compile_regexp_pattern (char *pat) /*{{{*/
2530 {
2531 SLRegexp_Type *re;
2532 unsigned int flags = SLREGEXP_CASELESS;
2533
2534 if (Slrn_UTF8_Mode) flags |= SLREGEXP_UTF8;
2535 if (NULL == (re = SLregexp_compile (pat, flags)))
2536 {
2537 slrn_error (_("Invalid regular expression or expression too long."));
2538 return NULL;
2539 }
2540 return re;
2541 }
2542
2543 /*}}}*/
2544
slrn_regexp_match(SLRegexp_Type * re,char * str)2545 unsigned char *slrn_regexp_match (SLRegexp_Type *re, char *str) /*{{{*/
2546 {
2547 return (unsigned char *)SLregexp_match (re, str, strlen (str));
2548 }
2549
2550 /*}}}*/
2551
2552 /*}}}*/
2553
slrn_is_fqdn(char * h)2554 int slrn_is_fqdn (char *h) /*{{{*/
2555 {
2556 char *p;
2557
2558 /* Believe it or not, I have come across one system with a '(' character
2559 * as part of the hostname!!! I suppose that I should also check for
2560 * other strange characters as well. This is an issue since a message
2561 * id will be composed from the fqdn. For that reason, such names will
2562 * be rejected. Sigh.
2563 */
2564 if (NULL != slrn_strbrk (h, "~`!@#$%^&*()=+|\\[]{}/?;"))
2565 return 0;
2566
2567 p = slrn_strbyte (h, '.');
2568 if ((p == NULL) || (p == h))
2569 return 0;
2570
2571 /* Make sure it does not end in a '.' */
2572 if (p [strlen(p)-1] == '.')
2573 return 0;
2574
2575 return 1;
2576 }
2577 /*}}}*/
2578
2579 /* Try to get a fully qualified domain name. */
get_hostname(void)2580 static char *get_hostname (void)
2581 {
2582 #ifdef HAVE_GETADDRINFO
2583 struct addrinfo hint, *res;
2584 int r;
2585 #else
2586 struct hostent *host_entry;
2587 #endif
2588 char buf[MAX_HOST_NAME_LEN + 1];
2589
2590 if ((-1 == gethostname (buf, MAX_HOST_NAME_LEN))
2591 || (*buf == 0))
2592 return NULL;
2593
2594 /* gethostname may not provide the full name so use gethostbyname
2595 * to get more information. Why isn't there a simplified interface to
2596 * get the FQDN!!!!
2597 */
2598 #ifdef HAVE_GETADDRINFO
2599 memset(&hint, 0, sizeof (hint));
2600 hint.ai_flags = AI_CANONNAME;
2601
2602 r = getaddrinfo(buf, NULL, &hint, &res);
2603 if (r == EAI_AGAIN)
2604 {
2605 slrn_sleep (2);
2606 r = getaddrinfo(buf, NULL, &hint, &res);
2607 }
2608
2609 if ((r == 0) && res && res->ai_canonname)
2610 {
2611 char *ret = slrn_safe_strmalloc (res->ai_canonname);
2612 freeaddrinfo(res);
2613 return ret;
2614 }
2615 #else
2616 host_entry = gethostbyname (buf);
2617
2618 # if defined(TRY_AGAIN) && !defined(MULTINET)
2619 if ((host_entry == NULL) && (h_errno == TRY_AGAIN))
2620 {
2621 slrn_sleep (2);
2622 host_entry = gethostbyname (buf);
2623 }
2624 # endif
2625
2626 if ((host_entry != NULL)
2627 && (host_entry->h_name != NULL)
2628 && (host_entry->h_name[0] != 0))
2629 {
2630 char **aliases;
2631
2632 if ((0 == slrn_is_fqdn ((char *)host_entry->h_name))
2633 && (NULL != (aliases = host_entry->h_aliases)))
2634 {
2635 while (*aliases != NULL)
2636 {
2637 if (slrn_is_fqdn (*aliases))
2638 return slrn_safe_strmalloc (*aliases);
2639 aliases++;
2640 }
2641 }
2642
2643 return slrn_safe_strmalloc ((char *)host_entry->h_name);
2644 }
2645 #endif
2646
2647 return slrn_safe_strmalloc (buf);
2648 }
2649
2650 #ifdef OUR_HOSTNAME
2651 /* Returns a pointer to a statically allocated area */
get_host_from_filename(char * file)2652 static char *get_host_from_filename (char *file)
2653 {
2654 FILE *fp;
2655 char *host;
2656 static char line[MAX_HOST_NAME_LEN + 1];
2657
2658 if (NULL == (fp = fopen (file, "r")))
2659 return NULL;
2660
2661 host = NULL;
2662 if (NULL != fgets (line, sizeof (line), fp))
2663 {
2664 slrn_trim_string (line);
2665 if (slrn_is_fqdn (line))
2666 host = line;
2667 }
2668
2669 fclose(fp);
2670 return host;
2671 }
2672 #endif /* OUR_HOSTNAME */
2673
slrn_get_user_info(void)2674 void slrn_get_user_info (void) /*{{{*/
2675 {
2676 char *name, *host, *host1, *org;
2677 #ifdef OUR_ORGANIZATION
2678 char *our_org = OUR_ORGANIZATION;
2679 #endif
2680 #ifdef HAS_PASSWORD_CODE
2681 struct passwd *pw;
2682 #endif
2683
2684 /* Fill in what is assumed to be non-NULL by rest of program. */
2685
2686 /* no-c-format tells gettext that the following strings do not
2687 * need to be checked as if they were passed to printf. */
2688
2689 Slrn_User_Info.followup_string = /* xgettext:no-c-format */
2690 slrn_safe_strmalloc (_("On %D, %r <%f> wrote:"));
2691 Slrn_User_Info.reply_string = /* xgettext:no-c-format */
2692 slrn_safe_strmalloc (_("In %n, you wrote:"));
2693 Slrn_User_Info.followupto_string = /* xgettext:no-c-format */
2694 slrn_safe_strmalloc (_("[\"Followup-To:\" header set to %n.]"));
2695
2696 Slrn_CC_Post_Message = /* xgettext:no-c-format */
2697 slrn_safe_strmalloc (_("[This message has also been posted to %n.]"));
2698
2699 /* Now get default values for rest. */
2700 host = get_hostname ();
2701 if (host != NULL)
2702 {
2703 if (slrn_is_fqdn (host))
2704 Slrn_User_Info.posting_host = slrn_safe_strmalloc (host);
2705 }
2706
2707 #if ! SLRN_HAS_STRICT_FROM
2708 /* Allow user chance to specify another hostname. However, it will not
2709 * affect the posting host.
2710 */
2711 if ((NULL != (host1 = getenv ("HOSTNAME")))
2712 && (0 == slrn_is_fqdn (host1)))
2713 #endif
2714 host1 = NULL;
2715
2716 /* If a value was compiled in, use it. */
2717 #ifdef OUR_HOSTNAME
2718 if (host1 == NULL)
2719 {
2720 host1 = OUR_HOSTNAME;
2721 /* If the value is a file, read the file for the FQDN */
2722 if (slrn_is_absolute_path (host1))
2723 host1 = get_host_from_filename (OUR_HOSTNAME);
2724 }
2725 #endif
2726
2727 if ((host1 != NULL)
2728 && slrn_is_fqdn (host1))
2729 {
2730 slrn_free (host);
2731 host = slrn_safe_strmalloc (host1);
2732 }
2733
2734 /* Finally!! */
2735 Slrn_User_Info.hostname = host;
2736
2737 #ifdef VMS
2738 name = slrn_vms_getlogin();
2739 #else
2740 name = NULL;
2741 # ifdef HAS_PASSWORD_CODE
2742 /* I cannot use getlogin under Unix because some implementations
2743 * truncate the username to 8 characters. Besides, I suspect that
2744 * it is equivalent to the following line.
2745 *
2746 * Also it is not clear if the valued returned by getpwuid is malloced.
2747 * The man page indicates that it _may_ point to a static area. Valgrind
2748 * reports a leak. Sigh.
2749 */
2750 pw = getpwuid (getuid ());
2751 if (pw != NULL)
2752 name = pw->pw_name;
2753 # endif
2754 #endif
2755
2756 if (((name == NULL) || (*name == 0))
2757 #if ! SLRN_HAS_STRICT_FROM
2758 && ((name = getenv("USER")) == NULL)
2759 && ((name = getenv("LOGNAME")) == NULL)
2760 #endif
2761 )
2762 name = "";
2763
2764 Slrn_User_Info.username = slrn_safe_strmalloc (name);
2765 Slrn_User_Info.login_name = slrn_safe_strmalloc (name);
2766
2767 if ((Slrn_User_Info.replyto = getenv ("REPLYTO")) == NULL)
2768 Slrn_User_Info.replyto = "";
2769 Slrn_User_Info.replyto = slrn_safe_strmalloc (Slrn_User_Info.replyto);
2770
2771 #ifdef VMS
2772 Slrn_User_Info.realname = slrn_vms_fix_fullname(slrn_vms_get_uaf_fullname());
2773 #else
2774 # if ! SLRN_HAS_STRICT_FROM
2775 Slrn_User_Info.realname = getenv ("NAME");
2776 # else
2777 Slrn_User_Info.realname = NULL;
2778 # endif
2779 if ((Slrn_User_Info.realname == NULL)
2780 # ifdef HAS_PASSWORD_CODE
2781 && ((pw == NULL) || ((Slrn_User_Info.realname = pw->pw_gecos) == NULL))
2782 # endif
2783 )
2784 {
2785 Slrn_User_Info.realname = "";
2786 }
2787 #endif
2788
2789 Slrn_User_Info.realname = slrn_safe_strmalloc (Slrn_User_Info.realname);
2790
2791 /* truncate at character used to delineate extra gecos fields */
2792 name = Slrn_User_Info.realname;
2793 while (*name && (*name != ',')) name++;
2794 *name = 0;
2795
2796 org = getenv ("ORGANIZATION");
2797 #ifdef OUR_ORGANIZATION
2798 if (org == NULL) org = our_org;
2799 #endif
2800 if (org != NULL)
2801 {
2802 /* Check to see if this is an organization file. */
2803 char orgbuf[512];
2804 if (slrn_is_absolute_path (org))
2805 {
2806 FILE *fporg;
2807 if (NULL != (fporg = fopen (org, "r")))
2808 {
2809 if (NULL != fgets (orgbuf, sizeof (orgbuf) - 1, fporg))
2810 {
2811 unsigned int orglen = strlen (orgbuf);
2812 if (orglen && (orgbuf[orglen - 1] == '\n'))
2813 orgbuf[orglen - 1] = 0;
2814 org = orgbuf;
2815 }
2816 slrn_fclose (fporg);
2817 }
2818 #ifdef OUR_ORGANIZATION
2819 else if (our_org == org)
2820 org = NULL;
2821 #endif
2822 }
2823 if (org != NULL)
2824 Slrn_User_Info.org = slrn_safe_strmalloc (org);
2825 }
2826
2827 Slrn_User_Info.signature = slrn_safe_strmalloc (SLRN_SIGNATURE_FILE);
2828
2829 #if SLRN_HAS_CANLOCK
2830 Slrn_User_Info.cancelsecret = slrn_safe_strmalloc ("");
2831 #endif
2832 #ifdef SLRN_SENDMAIL_COMMAND
2833 Slrn_SendMail_Command = slrn_safe_strmalloc (SLRN_SENDMAIL_COMMAND);
2834 #endif
2835 }
2836
2837 /*}}}*/
2838
2839 #define IS_ATEXT(x) (((x) > 0x20) && ((x) < 0x7f) && \
2840 (NULL == slrn_strbyte ("\"(),.:;<>@[\\]", (x))))
is_dot_atom(char * str)2841 static int is_dot_atom (char *str)
2842 {
2843 char ch = *str++;
2844 if (!IS_ATEXT (ch)) return 0;
2845 while ((ch = *str++))
2846 {
2847 if (ch == '.') ch = *str++;
2848 if (!IS_ATEXT (ch)) return 0;
2849 }
2850 return 1;
2851 }
2852
make_escaped_string(char * src,int is_comment)2853 static char *make_escaped_string (char *src, int is_comment)
2854 {
2855 unsigned int len, dlen;
2856 char ch, *p, *pmax;
2857 char *dest;
2858
2859 if ((src == NULL) || (*src == 0)) return NULL;
2860
2861 len = strlen (src);
2862 p = src;
2863 pmax = p + len;
2864 dlen = 0;
2865
2866 while (p < pmax)
2867 {
2868 switch (*p++)
2869 {
2870 case '\\':
2871 dlen++;
2872 break;
2873
2874 case '"':
2875 if (is_comment == 0)
2876 dlen++;
2877 break;
2878
2879 case '(': case ')':
2880 if (is_comment)
2881 dlen++;
2882 break;
2883 }
2884 }
2885
2886 dest = slrn_malloc (len + dlen + 3, 0, 1);
2887 if (dest == NULL)
2888 return NULL;
2889
2890 p = dest;
2891 if (is_comment)
2892 *p++ = '(';
2893 else
2894 *p++ = '"';
2895
2896 while (1)
2897 {
2898 ch = *src++;
2899 switch (ch)
2900 {
2901 case 0:
2902 if (is_comment)
2903 *p++ = ')';
2904 else
2905 *p++ = '"';
2906 *p = 0;
2907 return dest;
2908
2909 case '\\':
2910 *p++ = '\\';
2911 break;
2912
2913 case '"':
2914 if (is_comment == 0)
2915 *p++ = '\\';
2916 break;
2917
2918 case '(': case ')':
2919 if (is_comment)
2920 *p++ = '\\';
2921 break;
2922 }
2923
2924 *p++ = ch;
2925 }
2926 }
2927
2928 /* returns NULL upon failure */
make_localpart(char * username)2929 static char *make_localpart (char *username)
2930 {
2931 if ((username == NULL) || (*username == 0) )
2932 return NULL;
2933 if (is_dot_atom (username))
2934 {
2935 return slrn_safe_strmalloc(username);
2936 }
2937 return make_escaped_string (username, 0);
2938 }
2939
make_realname(char * realname)2940 static char *make_realname (char *realname)
2941 {
2942 char *p, *pmax;
2943 int flags;
2944 #define REALNAME_HAS_8BIT 0x1
2945 #define REALNAME_HAS_CTRL 0x2
2946 #define REALNAME_HAS_SPEC 0x4
2947
2948 if ((realname == NULL) || (*realname == 0) )
2949 return NULL;
2950 /*
2951 * If realname consists only of atom-text, or 8-bit, then it may
2952 * be encoded as an atom. If it contains specials, it must be encoded
2953 * as a quoted-string, or a comment. It illegal for an 8 bit character
2954 * to be in a quoted string since the text of a quoted string cannot
2955 * be mime-encoded.
2956 */
2957 p = realname;
2958 pmax = p + strlen (realname);
2959 flags = 0;
2960 while (p < pmax)
2961 {
2962 unsigned char ch = (unsigned char) *p++;
2963 if (ch & 0x80)
2964 {
2965 flags |= REALNAME_HAS_8BIT;
2966 continue;
2967 }
2968 switch (ch)
2969 {
2970 case '\r':
2971 case '\n':
2972 case 127:
2973 return NULL;
2974
2975 case '(': case ')': case '<': case '>': case '[':
2976 case ']': case ':': case '@': case '\\': case ',':
2977 case '.':
2978 case '"': /* not a special, but treated like one here */
2979 flags |= REALNAME_HAS_SPEC;
2980 break;
2981
2982 case ' ': case '\t':
2983 break;
2984
2985 default:
2986 if (ch < 32)
2987 {
2988 flags |= REALNAME_HAS_CTRL;
2989 break;
2990 }
2991 break;
2992 }
2993 }
2994
2995 if ((flags == 0) || (flags == REALNAME_HAS_8BIT))
2996 return slrn_strmalloc (realname, 1);
2997
2998 if (flags & REALNAME_HAS_8BIT)
2999 return make_escaped_string (realname, 1);
3000
3001 return make_escaped_string (realname, 0);
3002 }
3003
3004 /* This function returns a malloced string of the form "From: value" */
slrn_make_from_header(void)3005 char *slrn_make_from_header (void)
3006 {
3007 static char *buf;
3008 char *localpart, *realname, *msg;
3009
3010 #if ! SLRN_HAS_STRICT_FROM
3011 if ((1 == slrn_run_hooks (HOOK_MAKE_FROM_STRING, 0))
3012 && (0 == SLang_pop_slstring (&msg)))
3013 {
3014 if (*msg != 0)
3015 {
3016 char *prefix = "From: ";
3017 if (0 == strncmp (msg, "From: ", 6))
3018 prefix = "";
3019 buf = slrn_strjoin (prefix, msg, "");
3020 SLang_free_slstring (msg);
3021 return buf;
3022 }
3023 SLang_free_slstring (msg);
3024 /* Drop through to default */
3025 }
3026 #endif
3027 msg = NULL;
3028
3029 if (( localpart = make_localpart (Slrn_User_Info.username)) == NULL)
3030 {
3031 slrn_error (_("Cannot generate \"From:\" line without a valid username."));
3032 return NULL;
3033 }
3034 if ((NULL == Slrn_User_Info.hostname) ||
3035 (0 == *Slrn_User_Info.hostname))
3036 /* Note: we currently do not check whether hostname is valid */
3037 {
3038 slrn_error (_("Cannot generate \"From:\" line without a hostname."));
3039 return NULL;
3040 }
3041
3042 if (( realname = make_realname (Slrn_User_Info.realname)) != NULL)
3043 {
3044 buf=slrn_safe_malloc(6 + strlen(realname) +2 + strlen(localpart) + 1
3045 + strlen(Slrn_User_Info.hostname)+2);
3046 sprintf (buf, "From: %s <%s@%s>", realname, localpart, /* safe */
3047 Slrn_User_Info.hostname);
3048 slrn_free(realname);
3049 }
3050 else
3051 {
3052 buf=slrn_safe_malloc(6 + strlen(localpart) + 1
3053 + strlen(Slrn_User_Info.hostname)+2);
3054 sprintf (buf, "From: %s@%s", localpart, Slrn_User_Info.hostname); /* safe */
3055 }
3056
3057 slrn_free(localpart);
3058 return buf;
3059 }
3060
3061