source: trunk/third/transcript/src/milan/fpfilter.c @ 9090

Revision 9090, 19.0 KB checked in by ghudson, 28 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r9089, which included commits to RCS files with non-trunk default branches.
Line 
1/*
2 * Copyright Milan Technology Corp. 1991, 1992
3 */
4
5/*
6 * fpfilter.c -- FastPort communications interface program. See man page for
7 * complete set of options generates fpcomm for Adobe compatibility
8 */
9
10char           *VERSION = "@(#)fpfilter.c       2.2 10/15/92";
11
12#include "std.h"
13#include "dp.h"
14#include "errors.h"
15#include "udp.h"
16
17char           *g_filter_name;  /* The invocation name */
18s_options       g_opt;          /* the options struct */
19FILE           *g_errorLog=0;   /* log file for errors */
20
21long            fin_bytes;      /* Total number of bytes */
22long            act_bytes_sent = 0;     /* Number of bytes actually sent */
23long            int_bytes;      /* Number of par bytes initially */
24
25/* UDP Status packet type */
26
27extern udp_status_packet udp_stat;
28
29int             status_id = 0;
30
31/* SIGALARM interrupt handler. */
32int             g_alarmed = 0;
33#ifdef ANSI
34void
35to_alarm(int foo)
36#else
37void
38to_alarm(foo)
39int foo;
40#endif
41{
42#ifndef ESIX
43        signal(SIGALRM, to_alarm);
44#endif
45        g_alarmed = 1;
46}
47
48#ifdef ANSI
49void
50add_file(file_obj_ptr * flist, char *file_to_add)
51#else
52void
53add_file(flist, file_to_add)
54        file_obj_ptr   *flist;
55        char           *file_to_add;
56#endif
57{
58        file_obj_ptr    node, runner;
59        node = (file_obj_ptr) malloc(sizeof(file_obj_t));
60        node->next = 0;
61        strncpy(node->file_name, file_to_add, MAXNAMELEN);
62
63        if (!*flist)
64                *flist = node;
65        else {
66                runner = *flist;
67                while (runner->next)
68                        runner = runner->next;
69                runner->next = node;
70        }
71}
72
73#ifdef ANSI
74int             sendfile
75                (int sock, char *file_to_send, int output_dest, int check_postscript, char *printer_name)
76#else
77int
78sendfile(sock, file_to_send, output_dest, check_postscript, printer_name)
79        int             sock;
80        char           *file_to_send;
81        int             output_dest;
82        int             check_postscript;
83        char           *printer_name;
84#endif
85{
86        int             fd;
87        int             numchars, num_sent, total_sent;
88        int             length, filetype;
89        char            inputbuffer[MAX_BUFFER];
90        char           *databuffer;
91        char            ff = 12;
92        char            first_chars[MAX_MAGIC_HEADER];
93        char            error_string[MAXSTRNGLEN];
94        int             write_error_sent = 0;
95        int             i;
96
97        pause();
98        if (strcmp(file_to_send, "STDIN")) {
99                if ((fd = open(file_to_send, O_RDONLY, 0400)) < 0)
100                        return (1);
101        } else
102                fd = 0;
103
104        while ((numchars = read(fd, inputbuffer, MAX_BUFFER)) > 0) {
105                total_sent = 0;
106
107                databuffer = (g_opt.mapflg) ?
108                        expand_buffer(inputbuffer, numchars, &numchars) : inputbuffer;
109#ifndef SLOWSCO
110                /* Perform normal write operation */
111                write_buffer(sock, databuffer, numchars, printer_name, output_dest);
112                check_input(sock, output_dest, 0);
113#ifdef SCO
114                check_write(sock);
115#endif
116
117#else
118                /*
119                 * write only one byte to avoid any flow control problem
120                 * which SCO seems to handle pretty badly
121                 */
122                for (i = 0; i < numchars; i++) {
123                        check_write(sock);
124                        write_buffer(sock, &databuffer[i], 1, printer_name, output_dest);
125                }
126#endif
127        }
128        check_input(sock, output_dest, 2);
129        if (g_opt.ff_flag) {
130                write(sock, &ff, 1);
131                act_bytes_sent += 1;
132        }
133        close(fd);
134        return (numchars);
135}
136
137/*
138 * write a buffer to the socket sock On blocks it checks to see what error
139 * has occurred through both the data channel and udp status All alarms and
140 * alarm logic are handled here. Note--the alarm handling routine re-arms the
141 * timer alarm
142 */
143
144#ifdef ANSI
145void
146write_buffer(int sock, char *databuffer, int numchars, char *printer_name, int output_dest)
147#else
148void
149write_buffer(sock, databuffer, numchars, printer_name, output_dest)
150        int             sock;
151        char           *databuffer;
152        int             numchars;
153        char           *printer_name;
154        int             output_dest;
155#endif
156{
157        char            error_string[MAXSTRNGLEN];
158        int             total_sent = 0;
159        int             num_sent;
160        int             orig_total;
161
162#ifndef ESIX
163        signal(SIGALRM, to_alarm);
164#endif
165
166#ifdef BSD
167        alarm(60);
168#endif
169        orig_total = numchars;
170        while ((num_sent = write(sock, databuffer + total_sent, numchars)) != numchars) {
171                if (errno != EINTR && num_sent < 0)
172                        error_notify(ERR_WRITE, 0);
173
174                if (errno == EINTR) {
175                        error_string[0] = 0;
176                        get_printer_status(printer_name, error_string, g_opt.dataport);
177#ifdef BSD
178                        update_status_file(error_string, status_id, CREATE);
179#endif
180                        error_notify(ERR_GENERIC, error_string);
181                        check_input(sock, output_dest, 0);
182                        continue;
183                }
184                check_input(sock, output_dest, 0);
185                if (num_sent > 0) {
186                        numchars -= num_sent;
187                        total_sent += num_sent;
188                }
189#ifdef BSD
190                if (numchars == 0) {
191                        break;
192                } else
193                        alarm(10);
194#endif
195        }
196#ifdef BSD
197        alarm(0);               /* turn off the alarm after the write */
198#endif
199
200        /* Update # of characters sent so far */
201
202        act_bytes_sent += orig_total;
203}
204
205
206/*
207 * simply checks the read side of sock to see if there is any data to read
208 * back and writes it to output_dest
209 */
210
211#ifdef ANSI
212void
213check_input(int sock, int output_dest, int time_out)
214#else
215void
216check_input(sock, output_dest, time_out)
217        int             sock, output_dest, time_out;
218#endif
219{
220        struct timeval  timeout;
221        fd_set          readfd;
222        char            inchar;
223        int             num_chars;
224        int             sel_val;
225        char            buf[MAX_BUFFER];
226        char            error_string[MAXSTRNGLEN];
227        int             count = 0;
228
229        FD_ZERO(&readfd);
230
231        timeout.tv_sec = time_out;
232        timeout.tv_usec = 0;
233        FD_SET(sock, &readfd);
234        while (sel_val = select(sock + 1, &readfd, 0, 0, &timeout)) {
235                if (sel_val < 0)
236                        break;
237                if (FD_ISSET(sock, &readfd)) {
238                        if ((num_chars = read(sock, &inchar, 1)) >= 0) {
239                                if (count < MAX_BUFFER - 1)
240                                        buf[count++] = inchar;
241                                else {
242                                        buf[count] = (char) 0;
243                                        error_notify(ERR_GENERIC, buf);
244                                        count = 0;
245                                }
246                        } else
247                                break;
248                }
249        }
250        if (count > 0) {
251                buf[count] = (char) 0;
252                error_notify(ERR_GENERIC, buf);
253        }
254}
255
256#ifdef ANSI
257void
258send_control_d(int sock)
259#else
260void
261send_control_d(sock)
262        int             sock;
263#endif
264{
265        char            dchar = 4;      /* control-d if a postscript printer */
266        write(sock, &dchar, 1);
267
268        /* Keep track of # of chars actually written so far */
269
270        act_bytes_sent += 1;
271}
272
273#ifdef ANSI
274char           *
275expand_buffer(char *data, int length, int *retlength)
276#else
277char           *
278expand_buffer(data, length, retlength)
279        char           *data;
280        int             length;
281        int            *retlength;
282#endif
283{
284        static char     return_buff[2 * MAX_BUFFER];
285        int             temp, i;
286        for (i = 0, temp = 0; i < length; i++) {
287                if (data[i] == '\n') {
288                        return_buff[temp++] = '\r';
289                        return_buff[temp++] = '\n';
290                } else {
291                        return_buff[temp++] = data[i];
292                }
293        }
294        *retlength = temp;
295        return (return_buff);
296}
297
298/*
299 * send_banner() we need this since transcript writes a file .banner that we
300 * need to write to the printer
301 *
302 * ADOBE: assume that previous filters will handle BANNERPRO=file and write it
303 * to .banner
304 */
305
306#ifdef ANSI
307void
308send_banner(int sock)
309#else
310void
311send_banner(sock)
312        int             sock;
313#endif
314{
315        int             bfile;
316        char            input_b[512];
317        int             c_read, total = 0, num_sent = 0;
318
319        if ((bfile = open(".banner", O_RDONLY, 0600)) < 0)
320                return;
321        while ((c_read = read(bfile, input_b, 512)) > 0) {
322                act_bytes_sent += c_read;
323                while ((num_sent = write(sock, input_b + total, c_read))
324                       != c_read) {
325                        if (num_sent < 0)
326                                return;
327                        if (!num_sent)
328                                return;
329                        total += num_sent;
330                        c_read -= num_sent;
331                }
332        }
333        unlink(".banner");
334}
335
336/*
337 * Get the next printer from the linked list of printers and return the
338 * printer in first argument. Returns a zero if all OK, else returns -1.
339 */
340
341#ifdef ANSI
342int
343getNextPrinter(hsw_PCONFIG ** current_ptr, struct sockaddr_in * server)
344#else
345int
346getNextPrinter(current_ptr, server)
347        hsw_PCONFIG   **current_ptr;
348        struct sockaddr_in *server;
349#endif
350{
351        static int      valid_host_name = 0;
352        struct hostent *hp;
353        if (!*current_ptr)
354                *current_ptr = g_opt.prt_list;
355        else {
356                *current_ptr = (*current_ptr)->next_printer;
357                if (!*current_ptr)
358                        *current_ptr = g_opt.prt_list;
359        }
360
361        while (*current_ptr) {
362                if (hp = gethostbyname((*current_ptr)->printer_name)) {
363                        valid_host_name++;
364                        bcopy((char *) hp->h_addr, (char *) &server->sin_addr, hp->h_length);
365                        server->sin_port = htons((*current_ptr)->ptype);
366                        return (0);
367                } else {
368                        char            error_string[MAXSTRNGLEN];
369                        sprintf(error_string, "host name lookup failed for %s",
370                                (*current_ptr)->printer_name);
371                        error_notify(ERR_GENERIC, error_string);
372                        if (!(*current_ptr)->next_printer) {
373                                if (!valid_host_name) {
374                                        error_notify(ERR_GENERIC, "fpfilter: exit, no valid hosts specified");
375                                        exit(1);
376                                }
377                        }
378                }
379                *current_ptr = (*current_ptr)->next_printer;
380        }
381        if (valid_host_name)
382          return(1);
383        return(-1);
384}
385
386#ifdef ANSI
387main(int argc, char **argv)
388#else
389main(argc, argv)
390        int             argc;
391        char          **argv;
392#endif
393{
394        struct sockaddr_in server;
395        hsw_PCONFIG    *current_ptr;    /* Current printer */
396        char            c, *name, *temp, *cp;
397        char           *Autoconfig;
398        char            error_string[MAXSTRNGLEN];
399        int             val;
400        int             counter = 0;
401
402
403        /*
404         * set to stdout or stderr depending on from where the program is
405         * called
406         */
407        int             output_dest;
408
409        int             sock, sockops, optval;
410        int             was_waiting_for_printer = 0;
411        int             got_status = 0;
412
413
414#ifndef HPOLD
415        struct linger   linger_struct;
416#else
417        int             lingerval = 1;
418#endif
419
420#ifdef DEBUG
421        if (!access("/tmp/fpdebug", F_OK)) {
422                syslog(LOG_ERR, "%s %d\n", argv[0], getpid());
423                pause();
424        }
425#endif
426
427#ifndef ESIX
428#ifdef BSD
429        signal(SIGALRM, to_alarm);
430        signal(SIGCLD, sig_child);
431#else
432        signal(SIGCLD, SIG_IGN);
433        sigignore(SIGPIPE);
434#endif
435#endif
436
437        setDefaults(&g_opt);
438
439        checkForCurrentDir(argc, argv);
440
441        hsw_Getprinterconfig();
442
443#ifdef BSD
444        if (g_opt.acctg)
445                do_acctg(argv[8]);
446#endif
447
448        /* If an error file needs to be opened, do so */
449        if (g_opt.notify_type.file)
450                if (!(g_errorLog = fopen(g_opt.notify_type.filename, "a")))
451                        g_opt.notify_type.file = 0;
452
453        /* override with command line options */
454        output_dest = parseCommandLineArgs(argc, argv);
455
456        if (!g_opt.prt_list) {
457                char            printer_name[MAXNAMELEN];
458                get_printername(printer_name);
459                g_opt.prt_list =
460                        form_printer_list(printer_name,
461                                    g_opt.prt_list, g_opt.dataport, APPEND);
462        }
463        if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
464                error_notify(ERR_DOMAIN, 0);
465        server.sin_family = AF_INET;
466
467        current_ptr = 0;
468        if (getNextPrinter(&current_ptr, &server) == -1)
469                error_notify(ERR_NORESPONSE, 0);
470        g_alarmed = 0;
471        for (;;) {              /* loop as long as we don't get a fatal error
472                                 * this allows engine errors to be ridden
473                                 * through */
474                char            status_message[MAXSTRNGLEN];
475                char            temp_printer[MAXSTRNGLEN];
476                int             connect_error_sent = 0;
477
478#ifdef BSD
479                sprintf(status_message, "printing to %s port on %s\n",
480                        g_opt.dataport == PARALLEL ? "parallel" : "serial",
481                        current_ptr->printer_name);
482                update_status_file(status_message, status_id++, CREATE);
483#endif
484
485                strcpy(temp_printer, current_ptr->printer_name);
486
487#ifdef BSD
488                alarm(30);
489#endif
490
491                if (connect(sock, (struct sockaddr *) & server, sizeof(server)) < 0) {
492#ifdef BSD
493                        alarm(0);
494#endif
495                        close(sock);
496                        if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
497                                error_notify(ERR_DOMAIN, 0);
498
499                        sprintf(error_string, "Error on connect (errno = %d)\nPrinter Status from Fastport:\n", errno);
500                        was_waiting_for_printer = 1;
501                        get_printer_status(current_ptr->printer_name, error_string, g_opt.dataport);
502#ifdef BSD
503                        update_status_file(error_string, status_id, APPEND);
504#endif
505
506#ifdef BSD
507                        if (!connect_error_sent) {
508                                connect_error_sent = 1;
509                                error_notify(ERR_GENERIC, error_string);
510                        }
511#else
512                        if (!connect_error_sent) {
513                                if (got_printer_error(error_string)) {
514                                        connect_error_sent = 1;
515                                        error_notify(ERR_GENERIC, error_string);
516                                }
517                        }
518#endif
519                        if (getNextPrinter(&current_ptr, &server) == -1) {
520                          error_notify(ERR_NORESPONSE,0);
521                          exit(1);
522                        }
523                } else
524                        break;
525        }
526
527#ifdef BSD
528        alarm(0);
529#endif
530
531        status_id++;
532#ifdef BSD
533        if (was_waiting_for_printer) {
534                sprintf(error_string, "printing to %s port on %s\n", g_opt.dataport == PARALLEL ? "parallel" : "serial",
535                        current_ptr->printer_name);
536                update_status_file(error_string, status_id, CREATE);
537        }
538#endif
539
540        if (g_opt.closewait) {
541                /*
542                * Now that you have connected to the printer, check the printer
543                * status
544                */
545
546                if (! get_printer_status(current_ptr->printer_name, error_string, g_opt.dataport))
547                        got_status = 0;
548                else {
549                        got_status = 1;
550                        /* Check the number of bytes written so far on the serial and
551                         * parallel port */
552
553                        if (g_opt.dataport == PARALLEL)
554                                int_bytes = ntohl(udp_stat.parallel_bytes);     /* Initial # of parallel
555                                                                 * bytes */
556                        if (g_opt.dataport == SERIAL)
557                                int_bytes = ntohl(udp_stat.serial_bytes);       /* Initial # of serial
558                                                                 * bytes */
559                }
560
561        }
562
563#ifndef HPOLD
564        linger_struct.l_onoff = 1;
565        linger_struct.l_linger = LINGERVAL;
566
567#ifndef ATT
568#ifdef __STDC__
569        sockops = setsockopt(sock, SOL_SOCKET, SO_LINGER,
570                             (const char *)&linger_struct,
571                             sizeof(linger_struct));
572#else
573        sockops = setsockopt(sock, SOL_SOCKET, SO_LINGER,
574                             (char *)&linger_struct,
575                             sizeof(linger_struct));
576#endif /* __STDC__ */   
577       
578        if (sockops < 0)
579                fprintf(stderr, "setsockopt returned %d \n", sockops);
580#endif
581#else
582        sockops = setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &lingerval,
583                             sizeof(lingerval));
584        if (sockops < 0)
585                fprintf(stderr, "setsockopt returned %d for keepalive\n", sockops);
586#endif
587
588        optval = 1;
589#ifdef __STDC__
590        sockops = setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE,
591                             (const char *)&optval,
592                             sizeof(optval));
593#else   
594        sockops = setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE,
595                             (char *)&optval,
596                             sizeof(optval));
597#endif /* __STDC__ */   
598        if (sockops < 0)
599                fprintf(stderr, "setsockopt returned %d for keepalive\n", sockops);
600
601        if (g_opt.start_string) {
602                write(sock, g_opt.start_string, strlen(g_opt.start_string));
603                act_bytes_sent += strlen(g_opt.start_string);
604        }
605        if (g_opt.send_startfile)
606                sendfile(sock, g_opt.start_file, output_dest, 0, current_ptr->printer_name);
607
608        /*
609         * postscript printers really like control-d's.  So, if there was an
610         * engine problem this first control d will resync.  The last one
611         * will leave it that way.
612         */
613        if (g_opt.use_control_d)
614                send_control_d(sock);
615        /*
616         * check to see if it should send a banner page
617         */
618        if ((g_opt.real_filter || g_opt.dobanner) && g_opt.adobe.banner_first)
619                send_banner(sock);
620        /*
621         * if we have a list of files just send them one at a time
622         */
623        if (g_opt.file_list) {
624                while (g_opt.file_list) {
625                        if (sendfile(sock, g_opt.file_list->file_name,
626                                     output_dest, g_opt.check_postscript, current_ptr->printer_name))
627                                error_notify(ERR_SNDFILE, 0);
628                        g_opt.file_list = g_opt.file_list->next;
629                }
630                if ((g_opt.real_filter || g_opt.dobanner) && g_opt.adobe.banner_last)
631                        send_banner(sock);
632                if (g_opt.send_endfile)
633                        sendfile(sock, g_opt.end_file, output_dest, 0, current_ptr->printer_name);
634                if (g_opt.end_string) {
635                        write(sock, g_opt.end_string, strlen(g_opt.end_string));
636                        act_bytes_sent += strlen(g_opt.end_string);
637                }
638                if (g_opt.use_control_d)
639                        send_control_d(sock);
640        } else {
641                /*
642                 * Reading from standard input can either be through lpr or
643                 * just piping into the filter from the shell
644                 */
645
646                sendfile(sock, "STDIN", output_dest, g_opt.check_postscript, current_ptr->printer_name);
647                if ((g_opt.real_filter || g_opt.dobanner) && g_opt.adobe.banner_last)
648                        send_banner(sock);
649
650                if (g_opt.send_endfile)
651                        sendfile(sock, g_opt.end_file, output_dest, 0, current_ptr->printer_name);
652
653
654                if (g_opt.end_string) {
655                        write(sock, g_opt.end_string, strlen(g_opt.end_string));
656                        act_bytes_sent += strlen(g_opt.end_string);
657                }
658                if (g_opt.use_control_d)
659                        send_control_d(sock);
660        }
661
662        /* Now that you have finished printing, check the status again */
663
664        if (g_opt.closewait) {
665                int sent_status = 0;
666                if (! got_status ) {
667                    sleep(10);
668                } else
669                do {
670                        error_string[0] = 0;
671                        get_printer_status(current_ptr->printer_name, error_string, g_opt.dataport);
672                        if (counter > 0) {
673                                if ((! sent_status)  && (g_opt.dataport == PARALLEL) ) {
674                                        sent_status = 1;
675                                        if (got_printer_error(error_string)) {
676                                                error_notify(ERR_GENERIC, error_string);
677                                        }
678                                }
679                                check_input(sock, output_dest, 0);
680                                sleep(1);
681                        }
682
683                        /*
684                         * Check the number of bytes written so far on the
685                         * serial and parallel port
686                         */
687                        if (g_opt.dataport == PARALLEL)
688                                fin_bytes = ntohl(udp_stat.parallel_bytes);     /* Final # of par bytes */
689                        if (g_opt.dataport == SERIAL)
690                                fin_bytes = ntohl(udp_stat.serial_bytes);
691                        counter++;
692                }
693                while ((fin_bytes < (int_bytes + act_bytes_sent)) && (counter < 60));
694
695        }
696        close(sock);
697        if (g_opt.use_printer_classes) {
698                char            message[MAXSTRNGLEN];
699                sprintf(message, "The file was printed on %s \n", current_ptr->printer_name);
700                error_notify(ERR_GENERIC, message);
701        }
702        if (g_errorLog)
703                fclose(g_errorLog);
704        exit(0);
705}
706
707#ifdef BSD
708void
709#ifdef ANSI
710update_status_file(char *message, int status_num, int style)
711#else
712update_status_file(message, status_num, style)
713        char           *message;
714        int             status_num;
715        int             style;
716#endif
717{
718        int             sf;
719        static int      last_id = -1;
720
721        if (style == APPEND)
722                style = O_APPEND;
723        else
724                style = 0;
725
726        if ((sf = open("./status", O_RDWR | style, 0600)) >= 0) {
727                if (style == CREATE)
728                        ftruncate(sf, 0);
729                write(sf, message, strlen(message));
730                close(sf);
731        } else {
732                if (status_num != last_id) {
733                        error_notify(ERR_GENERIC, message);
734                        last_id = status_id;
735                }
736        }
737}
738
739#endif
740
741
742#ifdef SCO
743
744void
745check_write(sock)
746        int             sock;
747{
748
749        struct timeval  timeout;
750        fd_set          writefd;
751        int             sel_val;
752        struct pollfd   pollfds[20];
753        int             i;
754
755        for (i = 0; i < 20; i++)
756                pollfds[i].events = 0;
757
758        pollfds[sock].events = POLLOUT;
759        pollfds[sock].fd = sock;
760
761        while (1) {
762                if (poll(pollfds, 20, -1) < 0) {
763                        perror("Poll failed");
764                        exit(1);
765                }
766                if (pollfds[sock].revents == POLLOUT)
767                        return;
768        }
769}
770
771#endif
772
773int
774#ifdef ANSI
775got_printer_error(char *error_string)
776#else
777got_printer_error(error_string)
778        char           *error_string;
779#endif
780{
781        char           *c_ptr;
782        if (is_substring("OFFLINE", error_string))
783                return (1);
784        if (is_substring("FAULT", error_string))
785                return (1);
786        if (is_substring("PAPER", error_string))
787                return (1);
788        return (0);
789}
790
791int
792#ifdef ANSI
793is_substring(char *sub, char *src)
794#else
795is_substring(sub, src)
796        char           *sub, *src;
797#endif
798{
799        while (*src) {
800                if (!strncmp(src, sub, strlen(sub)))
801                        return (1);
802                src++;
803        }
804        return (0);
805}
806
807/*
808 * This routine performs accounting. Here we look at the '.banner' file
809 * generated by the output filter in the spool directory and append the
810 * contents of this file to the accounting file whose name and path are
811 * passed as the 8th argument to the filter program. This SHOULD be used only
812 * when you are printing through 'lpr' command and only on BSD systems.
813 */
814
815#ifdef BSD
816void
817do_acctg(file)
818        char           *file;
819{
820        FILE           *acctg, *banner;
821        char           *str;
822
823        str = (char *) malloc(80);
824
825        if ((acctg = fopen(file, "a")) == NULL) {
826                error_notify(ERR_GENERIC, "can not open accounting file");
827                return;
828        }
829        if ((banner = fopen("./.acct", "r")) == NULL){
830                error_notify(ERR_GENERIC, "can not perform accounting !");
831                return;
832        }
833        fgets(str, 80, banner);
834        fputs(str, acctg);
835        fclose(banner);
836        fclose(acctg);
837}
838#endif
Note: See TracBrowser for help on using the repository browser.