]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/console/console.c
utf-8 support on win32 by replacing fputs and fgets
[bacula/bacula] / bacula / src / console / console.c
1 /*
2  *
3  *   Bacula Console interface to the Director
4  *
5  *     Kern Sibbald, September MM
6  *
7  *     Version $Id$
8  */
9
10 /*
11    Copyright (C) 2000-2004 Kern Sibbald and John Walker
12
13    This library is free software; you can redistribute it and/or
14    modify it under the terms of the GNU Lesser General Public
15    License as published by the Free Software Foundation; either
16    version 2.1 of the License, or (at your option) any later version.
17
18    This library is distributed in the hope that it will be useful,
19    but WITHOUT ANY WARRANTY; without even the implied warranty of
20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21    Lesser General Public License for more details.
22
23    You should have received a copy of the GNU Lesser General Public
24    License along with this library; if not, write to the Free
25    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
26    MA 02111-1307, USA.
27
28  */
29
30 #include "bacula.h"
31 #include "console_conf.h"
32 #include "jcr.h"
33
34 #ifdef HAVE_CONIO
35 #include "conio.h"
36 #else
37 #define con_init(x)
38 #define con_term()
39 #define con_set_zed_keys();
40 #define trapctlc()
41 #define clrbrk()
42 #define usrbrk() 0
43 #endif
44
45 #ifdef HAVE_WIN32
46 #include <windows.h>
47 #include "../lib/winapi.h"
48 #define isatty(fd) (fd==0)
49 #endif
50
51 /* Exported variables */
52
53 #ifdef HAVE_CYGWIN
54 int rl_catch_signals;
55 #else
56 extern int rl_catch_signals;
57 #endif
58
59 /* Imported functions */
60 int authenticate_director(JCR *jcr, DIRRES *director, CONRES *cons);
61
62 /* Dummy functions */
63 int generate_daemon_event(JCR *jcr, const char *event) { return 1; }
64
65 /* Forward referenced functions */
66 static void terminate_console(int sig);
67 static int check_resources();
68 int get_cmd(FILE *input, const char *prompt, BSOCK *sock, int sec);
69 static int do_outputcmd(FILE *input, BSOCK *UA_sock);
70 void senditf(const char *fmt, ...);
71 void sendit(const char *buf);
72
73 extern "C" void got_sigstop(int sig);
74 extern "C" void got_sigcontinue(int sig);
75 extern "C" void got_sigtout(int sig);
76 extern "C" void got_sigtin(int sig);
77
78
79 /* Static variables */
80 static char *configfile = NULL;
81 static BSOCK *UA_sock = NULL;
82 static DIRRES *dir;
83 static FILE *output = stdout;
84 static bool tee = false;                  /* output to output and stdout */
85 static bool stop = false;
86 static int argc;
87 static int numdir;
88 static POOLMEM *args;
89 static char *argk[MAX_CMD_ARGS];
90 static char *argv[MAX_CMD_ARGS];
91
92
93 /* Command prototypes */
94 static int versioncmd(FILE *input, BSOCK *UA_sock);
95 static int inputcmd(FILE *input, BSOCK *UA_sock);
96 static int outputcmd(FILE *input, BSOCK *UA_sock);
97 static int teecmd(FILE *input, BSOCK *UA_sock);
98 static int quitcmd(FILE *input, BSOCK *UA_sock);
99 static int timecmd(FILE *input, BSOCK *UA_sock);
100 static int sleepcmd(FILE *input, BSOCK *UA_sock);
101
102
103 #define CONFIG_FILE "./bconsole.conf"   /* default configuration file */
104
105 static void usage()
106 {
107    fprintf(stderr, _(
108 "Copyright (C) 2000-2004 Kern Sibbald and John Walker\n"
109 "\nVersion: " VERSION " (" BDATE ") %s %s %s\n\n"
110 "Usage: bconsole [-s] [-c config_file] [-d debug_level]\n"
111 "       -c <file>   set configuration file to file\n"
112 "       -dnn        set debug level to nn\n"
113 "       -s          no signals\n"
114 "       -t          test - read configuration and exit\n"
115 "       -?          print this message.\n"
116 "\n"), HOST_OS, DISTNAME, DISTVER);
117 }
118
119
120 extern "C"
121 void got_sigstop(int sig)
122 {
123    stop = true;
124 }
125
126 extern "C"
127 void got_sigcontinue(int sig)
128 {
129    stop = false;
130 }
131
132 extern "C"
133 void got_sigtout(int sig)
134 {
135 // printf("Got tout\n");
136 }
137
138 extern "C"
139 void got_sigtin(int sig)
140 {
141 // printf("Got tin\n");
142 }
143
144
145 static int zed_keyscmd(FILE *input, BSOCK *UA_sock)
146 {
147    con_set_zed_keys();
148    return 1;
149 }
150
151 /*
152  * These are the @command
153  */
154 struct cmdstruct { const char *key; int (*func)(FILE *input, BSOCK *UA_sock); const char *help; };
155 static struct cmdstruct commands[] = {
156  { N_("input"),      inputcmd,     _("input from file")},
157  { N_("output"),     outputcmd,    _("output to file")},
158  { N_("quit"),       quitcmd,      _("quit")},
159  { N_("tee"),        teecmd,       _("output to file and terminal")},
160  { N_("sleep"),      sleepcmd,     _("sleep specified time")},
161  { N_("time"),       timecmd,      _("print current time")},
162  { N_("version"),    versioncmd,   _("print Console's version")},
163  { N_("exit"),       quitcmd,      _("exit = quit")},
164  { N_("zed_keyst"),  zed_keyscmd,  _("zed_keys = use zed keys instead of bash keys")},
165              };
166 #define comsize (sizeof(commands)/sizeof(struct cmdstruct))
167
168 static int do_a_command(FILE *input, BSOCK *UA_sock)
169 {
170    unsigned int i;
171    int stat;
172    int found;
173    int len;
174    char *cmd;
175
176    found = 0;
177    stat = 1;
178
179    Dmsg1(120, "Command: %s\n", UA_sock->msg);
180    if (argc == 0) {
181       return 1;
182    }
183
184    cmd = argk[0]+1;
185    if (*cmd == '#') {                 /* comment */
186       return 1;
187    }
188    len = strlen(cmd);
189    for (i=0; i<comsize; i++) {     /* search for command */
190       if (strncasecmp(cmd,  _(commands[i].key), len) == 0) {
191          stat = (*commands[i].func)(input, UA_sock);   /* go execute command */
192          found = 1;
193          break;
194       }
195    }
196    if (!found) {
197       pm_strcat(&UA_sock->msg, _(": is an illegal command\n"));
198       UA_sock->msglen = strlen(UA_sock->msg);
199       sendit(UA_sock->msg);
200    }
201    return stat;
202 }
203
204
205 static void read_and_process_input(FILE *input, BSOCK *UA_sock)
206 {
207    const char *prompt = "*";
208    bool at_prompt = false;
209    int tty_input = isatty(fileno(input));
210    int stat;
211
212    for ( ;; ) {
213       if (at_prompt) {                /* don't prompt multiple times */
214          prompt = "";
215       } else {
216          prompt = "*";
217          at_prompt = true;
218       }
219       if (tty_input) {
220          stat = get_cmd(input, prompt, UA_sock, 30);
221          if (usrbrk() == 1) {
222             clrbrk();
223          }
224          if (usrbrk()) {
225             break;
226          }
227       } else {
228          /* Reading input from a file */
229          int len = sizeof_pool_memory(UA_sock->msg) - 1;
230          if (usrbrk()) {
231             break;
232          }
233          if (fgets(UA_sock->msg, len, input) == NULL) {
234             stat = -1;
235          } else {
236             sendit(UA_sock->msg);  /* echo to terminal */
237             strip_trailing_junk(UA_sock->msg);
238             UA_sock->msglen = strlen(UA_sock->msg);
239             stat = 1;
240          }
241       }
242       if (stat < 0) {
243          break;                       /* error or interrupt */
244       } else if (stat == 0) {         /* timeout */
245          if (strcmp(prompt, "*") == 0) {
246             bnet_fsend(UA_sock, ".messages");
247          } else {
248             continue;
249          }
250       } else {
251          at_prompt = FALSE;
252          /* @ => internal command for us */
253          if (UA_sock->msg[0] == '@') {
254             parse_args(UA_sock->msg, &args, &argc, argk, argv, MAX_CMD_ARGS);
255             if (!do_a_command(input, UA_sock)) {
256                break;
257             }
258             continue;
259          }
260          if (!bnet_send(UA_sock)) {   /* send command */
261             break;                    /* error */
262          }
263       }
264       if (strcmp(UA_sock->msg, ".quit") == 0 || strcmp(UA_sock->msg, ".exit") == 0) {
265          break;
266       }
267       while ((stat = bnet_recv(UA_sock)) >= 0) {
268          if (at_prompt) {
269             if (!stop) {
270                sendit("\n");
271             }
272             at_prompt = false;
273          }
274          /* Suppress output if running in background or user hit ctl-c */
275          if (!stop && !usrbrk()) {
276             sendit(UA_sock->msg);
277          }
278       }
279       if (usrbrk() > 1) {
280          break;
281       } else {
282          clrbrk();
283       }
284       if (!stop) {
285          fflush(stdout);
286       }
287       if (is_bnet_stop(UA_sock)) {
288          break;                       /* error or term */
289       } else if (stat == BNET_SIGNAL) {
290          if (UA_sock->msglen == BNET_PROMPT) {
291             at_prompt = true;
292          }
293          Dmsg1(100, "Got poll %s\n", bnet_sig_to_ascii(UA_sock));
294       }
295    }
296 }
297
298 #ifdef HAVE_TLS
299 /*
300  * Call-back for reading a passphrase for an encrypted PEM file
301  * This function uses getpass(), which uses a static buffer and is NOT thread-safe.
302  */
303 static int tls_pem_callback(char *buf, int size, const void *userdata)
304 {
305    const char *prompt = (const char *) userdata;
306    char *passwd;
307
308    passwd = getpass(prompt);
309    bstrncpy(buf, passwd, size);
310
311    return (strlen(buf));
312 }
313 #endif
314
315
316 /*********************************************************************
317  *
318  *         Main Bacula Console -- User Interface Program
319  *
320  */
321 int main(int argc, char *argv[])
322 {
323    int ch, i, item;
324    bool no_signals = false;
325    bool test_config = false;
326    JCR jcr;
327
328    init_stack_dump();
329    my_name_is(argc, argv, "bconsole");
330    textdomain("bacula");
331    init_msg(NULL, NULL);
332    working_directory = "/tmp";
333    args = get_pool_memory(PM_FNAME);
334    con_init(stdin);
335
336    while ((ch = getopt(argc, argv, "bc:d:r:st?")) != -1) {
337       switch (ch) {
338       case 'c':                    /* configuration file */
339          if (configfile != NULL) {
340             free(configfile);
341          }
342          configfile = bstrdup(optarg);
343          break;
344
345       case 'd':
346          debug_level = atoi(optarg);
347          if (debug_level <= 0) {
348             debug_level = 1;
349          }
350          break;
351
352       case 's':                    /* turn off signals */
353          no_signals = true;
354          break;
355
356       case 't':
357          test_config = true;
358          break;
359
360       case '?':
361       default:
362          usage();
363          con_term();
364          exit(1);
365       }
366    }
367    argc -= optind;
368    argv += optind;
369
370    if (!no_signals) {
371       init_signals(terminate_console);
372    }
373
374 #if !defined(HAVE_WIN32)
375    /* Override Bacula default signals */
376    signal(SIGCHLD, SIG_IGN);
377    signal(SIGQUIT, SIG_IGN);
378    signal(SIGTSTP, got_sigstop);
379    signal(SIGCONT, got_sigcontinue);
380    signal(SIGTTIN, got_sigtin);
381    signal(SIGTTOU, got_sigtout);
382    trapctlc();
383 #else
384    InitWinAPIWrapper();
385 #endif
386      
387
388    if (argc) {
389       usage();
390       con_term();
391       exit(1);
392    }
393
394    if (configfile == NULL) {
395       configfile = bstrdup(CONFIG_FILE);
396    }
397
398    parse_config(configfile);
399
400    if (init_tls() != 0) {
401       Emsg0(M_ERROR_TERM, 0, _("TLS library initialization failed.\n"));
402    }
403
404    if (!check_resources()) {
405       Emsg1(M_ERROR_TERM, 0, _("Please correct configuration file: %s\n"), configfile);
406    }
407
408    if (test_config) {
409       terminate_console(0);
410       exit(0);
411    }
412
413    memset(&jcr, 0, sizeof(jcr));
414
415    (void)WSA_Init();                        /* Initialize Windows sockets */
416
417    if (numdir > 1) {
418       struct sockaddr client_addr;
419       memset(&client_addr, 0, sizeof(client_addr));
420       UA_sock = init_bsock(NULL, 0, "", "", 0, &client_addr);
421 try_again:
422       sendit(_("Available Directors:\n"));
423       LockRes();
424       numdir = 0;
425       foreach_res(dir, R_DIRECTOR) {
426          senditf( _("%d  %s at %s:%d\n"), 1+numdir++, dir->hdr.name, dir->address,
427             dir->DIRport);
428       }
429       UnlockRes();
430       if (get_cmd(stdin, _("Select Director: "), UA_sock, 600) < 0) {
431          (void)WSACleanup();               /* Cleanup Windows sockets */
432          return 1;
433       }
434       item = atoi(UA_sock->msg);
435       if (item < 0 || item > numdir) {
436          senditf(_("You must enter a number between 1 and %d\n"), numdir);
437          goto try_again;
438       }
439       LockRes();
440       dir = NULL;
441       for (i=0; i<item; i++) {
442          dir = (DIRRES *)GetNextRes(R_DIRECTOR, (RES *)dir);
443       }
444       UnlockRes();
445       term_bsock(UA_sock);
446    } else {
447       LockRes();
448       dir = (DIRRES *)GetNextRes(R_DIRECTOR, NULL);
449       UnlockRes();
450    }
451
452    LockRes();
453    CONRES *cons = (CONRES *)GetNextRes(R_CONSOLE, (RES *)NULL);
454    UnlockRes();
455
456    senditf(_("Connecting to Director %s:%d\n"), dir->address,dir->DIRport);
457
458 #ifdef HAVE_TLS
459    char buf[1024];
460    /* Initialize Console TLS context */
461    if (cons && (cons->tls_enable || cons->tls_require)) {
462       /* Generate passphrase prompt */
463       bsnprintf(buf, sizeof(buf), "Passphrase for Console \"%s\" TLS private key: ", cons->hdr.name);
464
465       /* Initialize TLS context:
466        * Args: CA certfile, CA certdir, Certfile, Keyfile,
467        * Keyfile PEM Callback, Keyfile CB Userdata, DHfile, Verify Peer */
468       cons->tls_ctx = new_tls_context(cons->tls_ca_certfile,
469          cons->tls_ca_certdir, cons->tls_certfile,
470          cons->tls_keyfile, tls_pem_callback, &buf, NULL, true);
471
472       if (!cons->tls_ctx) {
473          senditf(_("Failed to initialize TLS context for Console \"%s\".\n"),
474             dir->hdr.name);
475          terminate_console(0);
476          return 1;
477       }
478
479    }
480
481    /* Initialize Director TLS context */
482    if (dir->tls_enable || dir->tls_require) {
483       /* Generate passphrase prompt */
484       bsnprintf(buf, sizeof(buf), "Passphrase for Director \"%s\" TLS private key: ", dir->hdr.name);
485
486       /* Initialize TLS context:
487        * Args: CA certfile, CA certdir, Certfile, Keyfile,
488        * Keyfile PEM Callback, Keyfile CB Userdata, DHfile, Verify Peer */
489       dir->tls_ctx = new_tls_context(dir->tls_ca_certfile,
490          dir->tls_ca_certdir, dir->tls_certfile,
491          dir->tls_keyfile, tls_pem_callback, &buf, NULL, true);
492
493       if (!dir->tls_ctx) {
494          senditf(_("Failed to initialize TLS context for Director \"%s\".\n"),
495             dir->hdr.name);
496          terminate_console(0);
497          return 1;
498       }
499    }
500 #endif /* HAVE_TLS */
501
502    UA_sock = bnet_connect(NULL, 5, 15, "Director daemon", dir->address,
503                           NULL, dir->DIRport, 0);
504    if (UA_sock == NULL) {
505       terminate_console(0);
506       return 1;
507    }
508    jcr.dir_bsock = UA_sock;
509
510    /* If cons==NULL, default console will be used */
511    if (!authenticate_director(&jcr, dir, cons)) {
512       terminate_console(0);
513       return 1;
514    }
515
516    Dmsg0(40, "Opened connection with Director daemon\n");
517
518    sendit(_("Enter a period to cancel a command.\n"));
519
520    /* Run commands in ~/.bconsolerc if any */
521    char *env = getenv("HOME");
522    if (env) {
523       FILE *fd;
524       pm_strcpy(&UA_sock->msg, env);
525       pm_strcat(&UA_sock->msg, "/.bconsolerc");
526       fd = fopen(UA_sock->msg, "r");
527       if (fd) {
528          read_and_process_input(fd, UA_sock);
529          fclose(fd);
530       }
531    }
532
533    read_and_process_input(stdin, UA_sock);
534
535    if (UA_sock) {
536       bnet_sig(UA_sock, BNET_TERMINATE); /* send EOF */
537       bnet_close(UA_sock);
538    }
539
540    terminate_console(0);
541    return 0;
542 }
543
544
545 /* Cleanup and then exit */
546 static void terminate_console(int sig)
547 {
548
549    static bool already_here = false;
550
551    if (already_here) {                /* avoid recursive temination problems */
552       exit(1);
553    }
554    already_here = true;
555    cleanup_tls();
556    free_pool_memory(args);
557    con_term();
558    (void)WSACleanup();               /* Cleanup Windows sockets */
559    if (sig != 0) {
560       exit(1);
561    }
562    return;
563 }
564
565 /*
566  * Make a quick check to see that we have all the
567  * resources needed.
568  */
569 static int check_resources()
570 {
571    bool OK = true;
572    DIRRES *director;
573
574    LockRes();
575
576    numdir = 0;
577    foreach_res(director, R_DIRECTOR) {
578
579       numdir++;
580 #ifdef HAVE_TLS
581       /* tls_require implies tls_enable */
582       if (director->tls_require) {
583          director->tls_enable = true;
584       }
585
586       if ((!director->tls_ca_certfile && !director->tls_ca_certdir) && director->tls_enable) {
587          Emsg2(M_FATAL, 0, _("Neither \"TLS CA Certificate\""
588                              " or \"TLS CA Certificate Dir\" are defined for Director \"%s\" in %s."
589                              " At least one CA certificate store is required.\n"),
590                              director->hdr.name, configfile);
591          OK = false;
592       }
593 #endif /* HAVE_TLS */
594    }
595    
596    if (numdir == 0) {
597       Emsg1(M_FATAL, 0, _("No Director resource defined in %s\n"
598                           "Without that I don't how to speak to the Director :-(\n"), configfile);
599       OK = false;
600    }
601
602 #ifdef HAVE_TLS
603    CONRES *cons;
604    /* Loop over Consoles */
605    foreach_res(cons, R_CONSOLE) {
606       /* tls_require implies tls_enable */
607       if (cons->tls_require) {
608          cons->tls_enable = true;
609       }
610
611       if ((!cons->tls_ca_certfile && !cons->tls_ca_certdir) && cons->tls_enable) {
612          Emsg2(M_FATAL, 0, _("Neither \"TLS CA Certificate\""
613                              " or \"TLS CA Certificate Dir\" are defined for Console \"%s\" in %s.\n"),
614                              cons->hdr.name, configfile);
615          OK = false;
616       }
617    }
618 #endif /* HAVE_TLS */
619
620    UnlockRes();
621
622    return OK;
623 }
624
625
626 #ifdef HAVE_READLINE
627 #define READLINE_LIBRARY 1
628 #undef free
629 #include "readline.h"
630 #include "history.h"
631
632
633 int
634 get_cmd(FILE *input, const char *prompt, BSOCK *sock, int sec)
635 {
636    char *line;
637
638    rl_catch_signals = 0;              /* do it ourselves */
639    line = readline((char *)prompt);   /* cast needed for old readlines */
640
641    if (!line) {
642       exit(1);
643    }
644    strip_trailing_junk(line);
645    sock->msglen = pm_strcpy(&sock->msg, line);
646    if (sock->msglen) {
647       add_history(sock->msg);
648    }
649    free(line);
650    return 1;
651 }
652
653 #else /* no readline, do it ourselves */
654
655 /*
656  *   Returns: 1 if data available
657  *            0 if timeout
658  *           -1 if error
659  */
660 static int
661 wait_for_data(int fd, int sec)
662 {
663    fd_set fdset;
664    struct timeval tv;
665 #ifdef HAVE_WIN32
666    return 1;                          /* select doesn't seem to work on Win32 */
667 #endif
668
669    tv.tv_sec = sec;
670    tv.tv_usec = 0;
671    for ( ;; ) {
672       FD_ZERO(&fdset);
673       FD_SET((unsigned)fd, &fdset);
674       switch(select(fd + 1, &fdset, NULL, NULL, &tv)) {
675       case 0:                         /* timeout */
676          return 0;
677       case -1:
678          if (errno == EINTR || errno == EAGAIN) {
679             continue;
680          }
681          return -1;                  /* error return */
682       default:
683          return 1;
684       }
685    }
686 }
687
688 /*
689  * Get next input command from terminal.
690  *
691  *   Returns: 1 if got input
692  *            0 if timeout
693  *           -1 if EOF or error
694  */
695 int
696 get_cmd(FILE *input, const char *prompt, BSOCK *sock, int sec)
697 {
698    int len;
699    if (!stop) {
700       if (output == stdout || tee) {
701          sendit(prompt);
702       }
703    }
704 again:
705    switch (wait_for_data(fileno(input), sec)) {
706    case 0:
707       return 0;                    /* timeout */
708    case -1:
709       return -1;                   /* error */
710    default:
711       len = sizeof_pool_memory(sock->msg) - 1;
712       if (stop) {
713          sleep(1);
714          goto again;
715       }
716 #ifdef HAVE_CONIO
717       if (isatty(fileno(input))) {
718          input_line(sock->msg, len);
719          break;
720       }
721 #endif
722 #ifdef HAVE_WIN32 /* use special console for input on win32 */
723       if (input == stdin) {
724          if (win32_cgets(sock->msg, len) == NULL) {
725             return -1;
726          }
727       }
728       else
729 #endif
730       if (fgets(sock->msg, len, input) == NULL) {
731          return -1;
732
733       }
734       break;
735    }
736    if (usrbrk()) {
737       clrbrk();
738    }
739    strip_trailing_junk(sock->msg);
740    sock->msglen = strlen(sock->msg);
741    return 1;
742 }
743
744 #endif
745
746 static int versioncmd(FILE *input, BSOCK *UA_sock)
747 {
748    senditf("Version: " VERSION " (" BDATE ") %s %s %s\n",
749       HOST_OS, DISTNAME, DISTVER);
750    return 1;
751 }
752
753 static int inputcmd(FILE *input, BSOCK *UA_sock)
754 {
755    FILE *fd;
756
757    if (argc > 2) {
758       sendit(_("Too many arguments on input command.\n"));
759       return 1;
760    }
761    if (argc == 1) {
762       sendit(_("First argument to input command must be a filename.\n"));
763       return 1;
764    }
765    fd = fopen(argk[1], "r");
766    if (!fd) {
767       senditf(_("Cannot open file %s for input. ERR=%s\n"),
768          argk[1], strerror(errno));
769       return 1;
770    }
771    read_and_process_input(fd, UA_sock);
772    fclose(fd);
773    return 1;
774 }
775
776 /* Send output to both termina and specified file */
777 static int teecmd(FILE *input, BSOCK *UA_sock)
778 {
779    tee = true;
780    return do_outputcmd(input, UA_sock);
781 }
782
783 /* Send output to specified "file" */
784 static int outputcmd(FILE *input, BSOCK *UA_sock)
785 {
786    tee = false;
787    return do_outputcmd(input, UA_sock);
788 }
789
790
791 static int do_outputcmd(FILE *input, BSOCK *UA_sock)
792 {
793    FILE *fd;
794    const char *mode = "a+";
795
796    if (argc > 3) {
797       sendit(_("Too many arguments on output/tee command.\n"));
798       return 1;
799    }
800    if (argc == 1) {
801       if (output != stdout) {
802          fclose(output);
803          output = stdout;
804          tee = false;
805       }
806       return 1;
807    }
808    if (argc == 3) {
809       mode = argk[2];
810    }
811    fd = fopen(argk[1], mode);
812    if (!fd) {
813       senditf(_("Cannot open file %s for output. ERR=%s\n"),
814          argk[1], strerror(errno));
815       return 1;
816    }
817    output = fd;
818    return 1;
819 }
820
821 static int quitcmd(FILE *input, BSOCK *UA_sock)
822 {
823    return 0;
824 }
825
826 static int sleepcmd(FILE *input, BSOCK *UA_sock)
827 {
828    if (argc > 1) {
829       sleep(atoi(argk[1]));
830    }
831    return 1;
832 }
833
834
835 static int timecmd(FILE *input, BSOCK *UA_sock)
836 {
837    char sdt[50];
838    time_t ttime = time(NULL);
839    struct tm tm;
840    localtime_r(&ttime, &tm);
841    strftime(sdt, sizeof(sdt), "%d-%b-%Y %H:%M:%S", &tm);
842    sendit("\n");
843    return 1;
844 }
845
846 /*
847  * Send a line to the output file and or the terminal
848  */
849 void senditf(const char *fmt,...)
850 {
851     char buf[3000];
852     va_list arg_ptr;
853
854     va_start(arg_ptr, fmt);
855     bvsnprintf(buf, sizeof(buf), (char *)fmt, arg_ptr);
856     va_end(arg_ptr);
857     sendit(buf);
858 }
859
860 void sendit(const char *buf)
861 {
862 #ifdef xHAVE_CONIO
863     if (output == stdout || tee) {
864        char *p, *q;
865        /*
866         * Here, we convert every \n into \r\n because the
867         *  terminal is in raw mode when we are using
868         *  conio.
869         */
870        for (p=q=buf; (p=strchr(q, '\n')); ) {
871           if (p-q > 0) {
872              t_sendl(q, p-q);
873           }
874           t_sendl("\r\n", 2);
875           q = ++p;                    /* point after \n */
876        }
877        if (*q) {
878           t_send(q);
879        }
880     }
881     if (output != stdout) {
882        fputs(buf, output);
883     }
884 #else
885
886     fputs(buf, output);
887     fflush(output);
888     if (tee) {
889        fputs(buf, stdout);
890     }
891     if (output != stdout || tee) {
892        fflush(stdout);
893     }
894 #endif
895 }