"Fossies" - the Fresh Open Source Software Archive

Member "tin-2.6.3/src/screen.c" (23 Dec 2023, 17510 Bytes) of package /linux/misc/tin-2.6.3.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "screen.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.6.2_vs_2.6.3.

    1 /*
    2  *  Project   : tin - a Usenet reader
    3  *  Module    : screen.c
    4  *  Author    : I. Lea & R. Skrenta
    5  *  Created   : 1991-04-01
    6  *  Updated   : 2023-12-06
    7  *  Notes     :
    8  *
    9  * Copyright (c) 1991-2024 Iain Lea <iain@bricbrac.de>, Rich Skrenta <skrenta@pbm.com>
   10  * All rights reserved.
   11  *
   12  * Redistribution and use in source and binary forms, with or without
   13  * modification, are permitted provided that the following conditions
   14  * are met:
   15  *
   16  * 1. Redistributions of source code must retain the above copyright notice,
   17  *    this list of conditions and the following disclaimer.
   18  *
   19  * 2. Redistributions in binary form must reproduce the above copyright
   20  *    notice, this list of conditions and the following disclaimer in the
   21  *    documentation and/or other materials provided with the distribution.
   22  *
   23  * 3. Neither the name of the copyright holder nor the names of its
   24  *    contributors may be used to endorse or promote products derived from
   25  *    this software without specific prior written permission.
   26  *
   27  * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   28  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   30  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   31  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   37  * POSSIBILITY OF SUCH DAMAGE.
   38  */
   39 
   40 
   41 #ifndef TIN_H
   42 #   include "tin.h"
   43 #endif /* !TIN_H */
   44 #ifndef TCURSES_H
   45 #   include "tcurses.h"
   46 #endif /* !TCURSES_H */
   47 #ifndef TNNTP_H
   48 #   include "tnntp.h"
   49 #endif /* !TNNTP_H */
   50 
   51 int mark_offset = 0;
   52 
   53 static FILE* msglog = NULL;
   54 
   55 #ifndef USE_CURSES
   56     struct t_screen *screen;
   57 #endif /* !USE_CURSES */
   58 
   59 static void log_formatted_msg(const char* tag, const char *msg);
   60 
   61 /*
   62  * Move the cursor to the lower-left of the screen, where it won't be annoying
   63  */
   64 void
   65 stow_cursor(
   66     void)
   67 {
   68     if (!cmd_line)
   69         MoveCursor(cLINES, 0);
   70 }
   71 
   72 
   73 /*
   74  * helper for the various *_message() functions
   75  * returns a pointer to an allocated buffer with the formatted message
   76  * must be freed if not needed anymore
   77  */
   78 char *
   79 fmt_message(
   80     const char *fmt,
   81     va_list ap)
   82 {
   83     size_t size = LEN;
   84     char *msg = my_malloc(size);
   85     int used;
   86     va_list aq;
   87 
   88     while (1) {
   89         begin_va_copy(aq, ap);
   90         used = vsnprintf(msg, size, fmt, aq);
   91         end_va_copy(aq);
   92 
   93         if (used >= 0 && used < (int) size)
   94             break;
   95 
   96         size <<= 1;
   97         msg = my_realloc(msg, size);
   98     }
   99 
  100     return msg;
  101 }
  102 
  103 
  104 /*
  105  * Centre a formatted colour message at the bottom of the screen
  106  */
  107 void
  108 info_message(
  109     const char *fmt,
  110     ...)
  111 {
  112     char *buf;
  113     va_list ap;
  114 
  115     va_start(ap, fmt);
  116 
  117     clear_message();
  118 #ifdef HAVE_COLOR
  119     fcol(tinrc.col_message);
  120 #endif /* HAVE_COLOR */
  121 
  122     buf = fmt_message(fmt, ap);
  123     center_line(cLINES, FALSE, buf);    /* center the message at screen bottom */
  124     free(buf);
  125 
  126 #ifdef HAVE_COLOR
  127     fcol(tinrc.col_normal);
  128 #endif /* HAVE_COLOR */
  129     stow_cursor();
  130 
  131     va_end(ap);
  132 }
  133 
  134 
  135 /*
  136  * Print a formatted colour message at the bottom of the screen, wait a while
  137  */
  138 void
  139 wait_message(
  140     unsigned int sdelay,
  141     const char *fmt,
  142     ...)
  143 {
  144     char *buf, *msg;
  145     va_list ap;
  146 
  147     va_start(ap, fmt);
  148 
  149     clear_message();
  150 #ifdef HAVE_COLOR
  151     fcol(tinrc.col_message);
  152 #endif /* HAVE_COLOR */
  153 
  154     buf = fmt_message(fmt, ap);
  155     /* test for multiline messages */
  156     if (strrchr(buf, '\n')) {
  157         char *from, *to;
  158 
  159         for (from = buf; *from && (to = strchr(from, '\n')); from = ++to) {
  160             *to = '\0';
  161             msg = strunc(from, cCOLS - 1);
  162             my_fputs(msg, stdout);
  163             my_fputc('\n', stdout);
  164             free(msg);
  165         }
  166     } else {
  167         msg = strunc(buf, cCOLS - 1);
  168         my_fputs(msg, stdout);
  169         free(msg);
  170     }
  171     log_formatted_msg(NULL, buf);
  172     free(buf);
  173 
  174 #ifdef HAVE_COLOR
  175     fcol(tinrc.col_normal);
  176 #endif /* HAVE_COLOR */
  177     cursoron();
  178     my_flush();
  179     va_end(ap);
  180 
  181 #ifdef HAVE_SELECT
  182     /* allow to skip sleep time via key-press */
  183     {
  184         int nfds;
  185         fd_set readfds;
  186         struct timeval tv;
  187 
  188         forever {
  189             FD_ZERO(&readfds);
  190             FD_SET(STDIN_FILENO, &readfds);
  191             tv.tv_sec = sdelay;
  192             tv.tv_usec = 0;
  193 
  194 #   ifdef HAVE_SELECT_INTP
  195             nfds = select(STDIN_FILENO + 1, (int *) &readfds, NULL, NULL, &tv);
  196 #   else
  197             nfds = select(STDIN_FILENO + 1, &readfds, NULL, NULL, &tv);
  198 #   endif /* HAVE_SELECT_INTP */
  199             if (nfds == -1) {
  200 
  201                 if (errno != EINTR) {
  202                     perror_message("wait_message(select()) failed");
  203                     free(tin_progname);
  204                     giveup();
  205                 } else
  206                     return;
  207             } else
  208                 break;
  209         }
  210 
  211         if (nfds > 0) {
  212             if (FD_ISSET(STDIN_FILENO, &readfds)) {
  213 #   if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  214                 ReadWch();
  215 #   else
  216                 ReadCh();
  217 #   endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  218             }
  219         }
  220     }
  221 #else
  222     (void) sleep(sdelay);
  223 #endif /* HAVE_SELECT */
  224 }
  225 
  226 
  227 /*
  228  * Print a formatted message to stderr, no colour is added.
  229  * Interesting - this function implicitly clears 'errno'
  230  */
  231 void
  232 error_message(
  233     unsigned int sdelay,
  234     const char *fmt,
  235     ...)
  236 {
  237     char *buf;
  238     va_list ap;
  239 
  240     va_start(ap, fmt);
  241 
  242     errno = 0;
  243     clear_message();
  244 
  245     buf = fmt_message(fmt, ap);
  246     my_fputs(buf, stderr);  /* don't use my_fprintf() here due to %format chars */
  247     my_fflush(stderr);
  248     log_formatted_msg("ERR", buf);
  249     free(buf);
  250 
  251     if (cmd_line) {
  252         my_fputc('\n', stderr);
  253         fflush(stderr);
  254     } else {
  255         stow_cursor();
  256         (void) sleep(sdelay);
  257         clear_message();
  258     }
  259 
  260     va_end(ap);
  261 }
  262 
  263 
  264 /*
  265  * Print a formatted error message to stderr, no colour is added.
  266  * This function implicitly clears 'errno'
  267  */
  268 void
  269 perror_message(
  270     const char *fmt,
  271     ...)
  272 {
  273     char *buf;
  274     int err;
  275     va_list ap;
  276 
  277     err = errno;
  278     va_start(ap, fmt);
  279 
  280     clear_message();
  281 
  282     if ((buf = fmt_message(fmt, ap)) != NULL) {
  283         error_message(2, "%s: Error: %s", buf, strerror(err));
  284         free(buf);
  285     }
  286 
  287     va_end(ap);
  288 }
  289 
  290 
  291 void
  292 clear_message(
  293     void)
  294 {
  295     if (!cmd_line) {
  296         MoveCursor(cLINES, 0);
  297         CleartoEOLN();
  298         cursoroff();
  299 #ifndef USE_CURSES
  300         my_flush();
  301 #endif /* !USE_CURSES */
  302     }
  303 }
  304 
  305 
  306 void
  307 center_line(
  308     int line,
  309     t_bool inverse,
  310     const char *str)
  311 {
  312     char *ln;
  313     int pos;
  314     int len;
  315 
  316     len = strwidth(str);
  317 
  318 #if defined(HAVE_LIBICUUC) && defined(MULTIBYTE_ABLE) && defined(HAVE_UNICODE_UBIDI_H) && !defined(NO_LOCALE)
  319     if (tinrc.render_bidi && IS_LOCAL_CHARSET("UTF-8") && len > 1) {
  320         t_bool is_rtl;
  321 
  322         if ((ln = render_bidi(str, &is_rtl)) == NULL)
  323             ln = my_strdup(str);
  324     } else
  325 #endif /* HAVE_LIBICUUC && MULTIBYTE_ABLE && HAVE_UNICODE_UBIDI_H && !NO_LOCALE */
  326         ln = my_strdup(str);
  327 
  328     if (!cmd_line) {
  329         if (cCOLS >= len)
  330             pos = (cCOLS - len) / 2;
  331         else
  332             pos = 1;
  333 
  334         MoveCursor(line, pos);
  335         if (inverse) {
  336             StartInverse();
  337             my_flush();
  338         }
  339     }
  340 
  341     if (len >= cCOLS) {
  342         char *buffer;
  343 
  344         buffer = strunc(ln, cCOLS - 2);
  345         my_fputs(buffer, stdout);
  346         free(buffer);
  347     } else
  348         my_fputs(ln, stdout);
  349 
  350     if (cmd_line)
  351         my_flush();
  352     else {
  353         if (inverse)
  354             EndInverse();
  355     }
  356     free(ln);
  357 }
  358 
  359 
  360 void
  361 draw_arrow_mark(
  362     int line)
  363 {
  364 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  365     wchar_t *wtmp;
  366 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  367 
  368     MoveCursor(line, 0);
  369 
  370     if (tinrc.draw_arrow) {
  371 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  372         if (tinrc.utf8_graphics) {
  373             my_fputwc(CURSOR_HORIZ, stdout);
  374             my_fputwc(CURSOR_ARROW, stdout);
  375         } else
  376 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  377             my_fputs("->", stdout);
  378     } else {
  379 #ifdef USE_CURSES
  380         char buffer[BUFSIZ];
  381         char *s = screen_contents(line, 0, buffer);
  382 #else
  383         char *s = screen[line - INDEX_TOP].col;
  384 #endif /* USE_CURSES */
  385 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  386         if ((wtmp = char2wchar_t(s)) != NULL) {
  387             StartInverse();
  388             my_fputws(wtmp, stdout);
  389             EndInverse();
  390             if (mark_offset && wtmp[mark_offset + (art_mark_width - wcwidth(tinrc.art_marked_selected))] == tinrc.art_marked_selected) {
  391                 MoveCursor(line, mark_offset + (art_mark_width - wcwidth(tinrc.art_marked_selected)));
  392 /*              EndInverse(); */ /* needed? */
  393                 my_fputwc((wint_t) wtmp[mark_offset + (art_mark_width - wcwidth(tinrc.art_marked_selected))], stdout);
  394             }
  395             free(wtmp);
  396         }
  397 #else
  398         StartInverse();
  399         my_fputs(s, stdout);
  400         EndInverse();
  401         if (mark_offset && s[mark_offset] == tinrc.art_marked_selected) {
  402             MoveCursor(line, mark_offset);
  403 /*          EndInverse(); */ /* needed? */
  404             my_fputc(s[mark_offset], stdout);
  405         }
  406 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  407     }
  408     stow_cursor();
  409 }
  410 
  411 
  412 void
  413 erase_arrow(
  414     void)
  415 {
  416     int line = INDEX_TOP + currmenu->curr - currmenu->first;
  417 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  418     wchar_t *wtmp;
  419 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  420 
  421     if (!currmenu->max)
  422         return;
  423 
  424     MoveCursor(line, 0);
  425 
  426     if (tinrc.draw_arrow)
  427         my_fputs("  ", stdout);
  428     else {
  429 #ifdef USE_CURSES
  430         char buffer[BUFSIZ];
  431         char *s = screen_contents(line, 0, buffer);
  432 #else
  433         char *s;
  434 
  435         if (line - INDEX_TOP < 0) /* avoid underruns */
  436             line = INDEX_TOP;
  437 
  438         s = screen[line - INDEX_TOP].col;
  439 #endif /* USE_CURSES */
  440         EndInverse();
  441 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  442         if ((wtmp = char2wchar_t(s)) != NULL) {
  443             my_fputws(wtmp, stdout);
  444             if (mark_offset && wtmp[mark_offset + (art_mark_width - wcwidth(tinrc.art_marked_selected))] == tinrc.art_marked_selected) {
  445                 MoveCursor(line, mark_offset + (art_mark_width - wcwidth(tinrc.art_marked_selected)));
  446                 StartInverse();
  447                 my_fputwc((wint_t) wtmp[mark_offset + (art_mark_width - wcwidth(tinrc.art_marked_selected))], stdout);
  448                 EndInverse();
  449             }
  450             free(wtmp);
  451         }
  452 #else
  453         my_fputs(s, stdout);
  454         if (mark_offset && s[mark_offset] == tinrc.art_marked_selected) {
  455             MoveCursor(line, mark_offset);
  456             StartInverse();
  457             my_fputc(s[mark_offset], stdout);
  458             EndInverse();
  459         }
  460 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  461     }
  462 }
  463 
  464 
  465 void
  466 show_title(
  467     const char *title)
  468 {
  469     char keyhelp[MAXKEYLEN];
  470     char *helps;
  471     const char *sign;
  472     int col;
  473 
  474     if (tinrc.show_help_mail_sign != SHOW_SIGN_NONE) {
  475         col = MAXKEYLEN + strlen(_(txt_type_h_for_help)) + 1;
  476         helps = my_malloc(col);
  477 
  478         switch (signal_context) {
  479             case cSelect:
  480                 PrintFuncKey(keyhelp, GLOBAL_HELP, select_keys);
  481                 break;
  482 
  483             case cGroup:
  484                 PrintFuncKey(keyhelp, GLOBAL_HELP, group_keys);
  485                 break;
  486 
  487             case cThread:
  488                 PrintFuncKey(keyhelp, GLOBAL_HELP, thread_keys);
  489                 break;
  490 
  491             default:
  492                 keyhelp[0] = 'h';
  493                 keyhelp[1] = '\0';
  494         }
  495         snprintf(helps, col, _(txt_type_h_for_help), keyhelp);
  496 
  497         switch (tinrc.show_help_mail_sign) {
  498             case SHOW_SIGN_MAIL:
  499                 sign = mail_check(mailbox) ? _(txt_you_have_mail) : NULL;
  500                 break;
  501 
  502             case SHOW_SIGN_BOTH:
  503                 sign = mail_check(mailbox) ? _(txt_you_have_mail) : helps;
  504                 break;
  505 
  506             default:
  507                 sign = helps;
  508                 break;
  509         }
  510 
  511         if (sign) {
  512             col = cCOLS - strwidth(sign);
  513             if (col > 0) {
  514                 MoveCursor(0, col);
  515 #ifdef HAVE_COLOR
  516                 fcol(tinrc.col_title);
  517 #endif /* HAVE_COLOR */
  518                 /* you have mail message in */
  519                 my_fputs(sign, stdout);
  520 
  521 #ifdef HAVE_COLOR
  522                 fcol(tinrc.col_normal);
  523 #endif /* HAVE_COLOR */
  524             }
  525         }
  526         free(helps);
  527     }
  528     center_line(0, TRUE, title); /* wastes some space on the left */
  529 }
  530 
  531 
  532 void
  533 ring_bell(
  534     void)
  535 {
  536 #ifdef USE_CURSES
  537     if (!cmd_line)
  538         beep();
  539     else {
  540 #endif /* USE_CURSES */
  541     my_fputc('\007', stdout);
  542     my_flush();
  543 #ifdef USE_CURSES
  544     }
  545 #endif /* USE_CURSES */
  546 }
  547 
  548 
  549 void
  550 spin_cursor(
  551     void)
  552 {
  553     static const char buf[] = "|/-\\|/-\\ "; /* don't remove the tailing space! */
  554     static unsigned short int i = 0;
  555 
  556     if (batch_mode)
  557         return;
  558 
  559     if (i > 7)
  560         i = 0;
  561 
  562 #ifdef HAVE_COLOR
  563     fcol(tinrc.col_message);
  564 #endif /* HAVE_COLOR */
  565     my_printf("\b%c", buf[i++]);
  566     my_flush();
  567 #ifdef HAVE_COLOR
  568     fcol(tinrc.col_normal);
  569 #endif /* HAVE_COLOR */
  570 }
  571 
  572 
  573 #if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETTIMEOFDAY)
  574 #   define DISPLAY_FMT "%s %3d%% "
  575 #else
  576 #   define DISPLAY_FMT "%s %3d%%"
  577 #endif /* HAVE_CLOCK_GETTIME || HAVE_GETTIMEOFDAY */
  578 /*
  579  * progressmeter in %
  580  */
  581 void
  582 show_progress(
  583     const char *txt,
  584     t_artnum count,
  585     t_artnum total)
  586 {
  587     char display[LEN];
  588     int ratio;
  589     time_t curr_time;
  590     static char last_display[LEN];
  591     static int last_ratio;
  592     static t_artnum last_count;
  593     static t_artnum last_total;
  594     static time_t last_update;
  595 #if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETTIMEOFDAY)
  596     static int average;
  597     static int samples;
  598     static int last_secs_left;
  599     static int sum;
  600     char *display_format;
  601     int time_diff;
  602     int secs_left;
  603     t_artnum count_diff;
  604     static struct t_tintime last_time;
  605     static struct t_tintime this_time;
  606 #endif /* HAVE_CLOCK_GETTIME || HAVE_GETTIMEOFDAY */
  607 
  608     if (batch_mode || count <= 0 || total <= 1)
  609         return;
  610 
  611     /* If this is a new progress meter, start recalculating */
  612     if ((last_total != total) || (count <= last_count)) {
  613         last_ratio = -1;
  614         last_display[0] = '\0';
  615         last_update = time(NULL) - 2;
  616     }
  617 
  618     curr_time = time(NULL);
  619     ratio = (int) ((count * 100) / total);
  620     if ((ratio == last_ratio) && (curr_time - last_update < 2))
  621         /*
  622          * return if ratio did not change and less than
  623          * 2 seconds since last update to reduce output
  624          */
  625         return;
  626 
  627     last_update = curr_time;
  628 
  629 #if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETTIMEOFDAY)
  630     display_format = my_malloc(strlen(DISPLAY_FMT) + strlen(_(txt_remaining)) + 1);
  631     strcpy(display_format, DISPLAY_FMT);
  632 
  633     if (last_ratio == -1) {
  634         /* Don't print the time remaining */
  635         snprintf(display, sizeof(display), display_format, txt, ratio);
  636 
  637         /* Reset the variables */
  638         sum = average = samples = last_secs_left = 0;
  639     } else {
  640         /* Get the current time */
  641         tin_gettime(&this_time);
  642         time_diff = (int) ((this_time.tv_sec - last_time.tv_sec) * 1000000);
  643         time_diff = (int) (time_diff + ((this_time.tv_nsec - last_time.tv_nsec) / 1000));
  644         count_diff = (count - last_count);
  645 
  646         if (!count_diff) /* avoid div by zero */
  647             count_diff++;
  648 
  649         /*
  650          * Calculate a running average based on the last 20 samples. For the
  651          * first 19 samples just add all and divide by the number of samples.
  652          * From the 20th sample on use only the last 20 samples to calculate
  653          * the running averave. To make things easier we don't want to store
  654          * and keep track of all of them, so we assume that the first sample
  655          * was close to the current average and subtract it from sum. Then,
  656          * the new sample is added to the sum and the sum is divided by 20 to
  657          * get the new average.
  658          */
  659         if (samples == 20) {
  660             sum -= average;
  661             sum = (int) (sum + (time_diff / count_diff));
  662             average = sum / 20;
  663         } else {
  664             sum = (int) (sum + (time_diff / count_diff));
  665             average = sum / ++samples;
  666         }
  667 
  668         if (average >= 1000000)
  669             secs_left = (int) ((total - count) * (average / 1000000));
  670         else
  671             secs_left = (int) (((total - count) * average) / 1000000);
  672 
  673         if (secs_left < 0)
  674             secs_left = 0;
  675 
  676         if ((secs_left > 0) && (last_secs_left == 0))
  677             last_secs_left = secs_left;
  678 
  679         if (samples < 5)
  680             /* Don't print the time remaining */
  681             snprintf(display, sizeof(display), display_format, txt, ratio);
  682         else {
  683             /* Don't allow time remaining to increase by 1 or 2 seconds */
  684             if ((secs_left == last_secs_left + 1) || (secs_left == last_secs_left + 2))
  685                 secs_left = last_secs_left;
  686             else if (secs_left < last_secs_left)
  687                 last_secs_left = secs_left;
  688             strcat(display_format, _(txt_remaining));
  689             snprintf(display, sizeof(display), display_format, txt, ratio, secs_left / 60, secs_left % 60);
  690         }
  691     }
  692     free(display_format);
  693 
  694     tin_gettime(&last_time);
  695 #else
  696     snprintf(display, sizeof(display), DISPLAY_FMT, txt, ratio);
  697 #endif /* HAVE_CLOCK_GETTIME || HAVE_GETTIMEOFDAY */
  698 
  699     /* Only display text if it changed from last time */
  700     if (strcmp(display, last_display)) {
  701         char *tmp;
  702 
  703         if (RawState()) {
  704             clear_message();
  705             MoveCursor(cLINES, 0);
  706         } else {
  707             my_printf("\r");
  708             my_flush();
  709             CleartoEOLN();
  710         }
  711 
  712 #ifdef HAVE_COLOR
  713         if (RawState())
  714             fcol(tinrc.col_message);
  715 #endif /* HAVE_COLOR */
  716 
  717         /*
  718          * TODO: depending on the length of the newsgroup name
  719          * it's possible to cut away a great part of the progress meter
  720          * perhaps we should shorten the newsgroup name instead?
  721          */
  722         my_printf("%s", sized_message(&tmp, "%s", display));
  723         free(tmp);
  724 
  725 #ifdef HAVE_COLOR
  726         if (RawState())
  727             fcol(tinrc.col_normal);
  728 #endif /* HAVE_COLOR */
  729 
  730 #ifndef USE_CURSES
  731         if (!RawState())
  732             MoveCursor(cLINES, 0);
  733 #endif /* !USE_CURSES */
  734 
  735         my_flush();
  736         STRCPY(last_display, display);
  737     }
  738 
  739     last_count = count;
  740     last_total = total;
  741     last_ratio = ratio;
  742 }
  743 
  744 
  745 void
  746 open_msglog(
  747     void)
  748 {
  749     char logfile[PATH_LEN];
  750     char serverdir[PATH_LEN];
  751 
  752     if (msglog != NULL)
  753         return;
  754 
  755 #ifdef NNTP_ABLE
  756     if (read_news_via_nntp && !read_saved_news && nntp_tcp_port != IPPORT_NNTP)
  757         snprintf(logfile, sizeof(logfile), "%s:%u", nntp_server, nntp_tcp_port);
  758     else
  759 #endif /* NNTP_ABLE */
  760     {
  761         snprintf(logfile, sizeof(logfile), "%s", nntp_server);
  762     }
  763     joinpath(serverdir, sizeof(serverdir), rcdir, logfile);
  764     joinpath(logfile, sizeof(logfile), serverdir, "msglog");
  765 
  766     if ((msglog = fopen(logfile, "w")) != NULL) {
  767 #ifdef HAVE_FCHMOD
  768         fchmod(fileno(msglog), (mode_t) (S_IRUSR|S_IWUSR));
  769 #else
  770 #   ifdef HAVE_CHMOD
  771         chmod(logfile, (mode_t) (S_IRUSR|S_IWUSR));
  772 #   endif /* HAVE_CHMOD */
  773 #endif /* HAVE_FCHMOD */
  774     }
  775 }
  776 
  777 
  778 void
  779 close_msglog(
  780     void)
  781 {
  782     if (msglog)
  783         fclose(msglog);
  784     msglog = NULL;
  785 }
  786 
  787 
  788 void
  789 log_formatted_msg(
  790     const char *tag,
  791     const char *msg)
  792 {
  793 
  794     if (msglog == NULL || msg == NULL || strlen(msg) == 0)
  795         return;
  796 
  797     if (tag)
  798         fprintf(msglog, "%s: %s", tag, msg);
  799     else
  800         fprintf(msglog, "%s", msg);
  801 
  802     if (msg[strlen(msg) - 1] != '\n')
  803         fputc('\n', msglog);
  804 
  805     fflush(msglog);
  806 }