1 #if !defined(lint) && !defined(DOS)
2 static char rcsid[] = "$Id: titlebar.c 1075 2008-06-04 00:19:39Z hubert@u.washington.edu $";
3 #endif
4 
5 /*
6  * ========================================================================
7  * Copyright 2013-2021 Eduardo Chappa
8  * Copyright 2006-2008 University of Washington
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  *     http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * ========================================================================
17  */
18 
19 #include "headers.h"
20 #include "titlebar.h"
21 #include "folder.h"
22 #include "../pith/state.h"
23 #include "../pith/bitmap.h"
24 #include "../pith/msgno.h"
25 #include "../pith/thread.h"
26 #include "../pith/conf.h"
27 #include "../pith/init.h"
28 #include "../pith/sort.h"
29 #include "../pith/news.h"
30 #include "../pith/util.h"
31 #include "../pith/folder.h"
32 
33 /*
34  * Internal prototypes
35  */
36 int   digit_count(long);
37 void  output_titlebar(TITLE_S *);
38 char  sort_letter(SortOrder);
39 char *percentage(long, long, int);
40 
41 
42 /*
43  * some useful macros...
44  */
45 #define	MS_DEL			(0x01)
46 #define	MS_NEW			(0x02)
47 #define	MS_ANS			(0x04)
48 #define	MS_FWD			(0x08)
49 
50 #define	STATUS_BITS(X)	(!(X && (X)->valid) ? 0				      \
51 			   : (X)->deleted ? MS_DEL			      \
52 			     : (X)->answered ? MS_ANS			      \
53 				: (as.stream && user_flag_is_set(as.stream, (X)->msgno, FORWARDED_FLAG)) ? MS_FWD \
54 				   : (as.stream				      \
55 				      && (ps_global->unseen_in_view	      \
56 				          || (!(X)->seen		      \
57 					      && (!IS_NEWS(as.stream)	      \
58 					          || F_ON(F_FAKE_NEW_IN_NEWS, \
59 						          ps_global)))))      \
60 				        ? MS_NEW : 0)
61 
62 #define	BAR_STATUS(X)	(((X) & MS_DEL) ? "DEL"   \
63 			 : ((X) & MS_ANS) ? "ANS"   \
64 			  : ((X) & MS_FWD) ? "FWD"   \
65 		           : (as.stream		      \
66 			      && (!IS_NEWS(as.stream)   \
67 				  || F_ON(F_FAKE_NEW_IN_NEWS, ps_global)) \
68 			      && ((X) & MS_NEW)) ? "NEW" : "   ")
69 
70 
71 static struct titlebar_state {
72     MAILSTREAM	*stream;
73     MSGNO_S	*msgmap;
74     char	*title,
75 		*folder_name,
76 		*context_name;
77     long	 current_msg,
78 		 current_line,
79 		 current_thrd,
80 		 total_lines;
81     int		 msg_state,
82 		 cur_mess_col,
83 		 del_column,
84 		 percent_column,
85 		 page_column,
86 		 screen_cols,
87 		 pushed;
88     enum	 {Normal, OnlyRead, Closed} stream_status;
89     TitleBarType style;
90     TITLE_S      titlecontainer;
91 } as, titlebar_stack;
92 
93 
94 static int titlebar_is_dirty = 1;
95 
96 char *as_fname;		/* folder name */
97 char *as_cname;		/* context name */
98 
99 void
push_titlebar_state(void)100 push_titlebar_state(void)
101 {
102     as.pushed = 1;
103     titlebar_stack     = as;
104     if(as_fname) fs_give((void **)&as_fname);
105     as_fname = cpystr(as.folder_name);
106     if(as_cname) fs_give((void **)&as_cname);
107     as_cname = cpystr(as.context_name);
108     if(as.folder_name) fs_give((void **)&as.folder_name);
109     if(as.context_name) fs_give((void **)&as.context_name);
110 }
111 
112 
113 void
pop_titlebar_state(void)114 pop_titlebar_state(void)
115 {
116     /* guard against case where push pushed no state */
117     if(titlebar_stack.style != TitleBarNone){
118 	fs_give((void **)&(as.folder_name)); /* free malloc'd values */
119 	fs_give((void **)&(as.context_name));
120 	as = titlebar_stack;
121 	if(as.pushed){
122 	  as.folder_name = as_fname ? cpystr(as_fname) : NULL;
123 	  as.context_name = as_cname ? cpystr(as_cname): NULL;
124 	}
125 	as.pushed = 0;
126     }
127 }
128 
129 
130 int
digit_count(long int n)131 digit_count(long int n)
132 {
133     int i;
134 
135     return((n > 9)
136 	     ? (1 + (((i = digit_count(n / 10L)) == 3 || i == 7) ? i+1 : i))
137 	     : 1);
138 }
139 
140 
141 void
mark_titlebar_dirty(void)142 mark_titlebar_dirty(void)
143 {
144     titlebar_is_dirty = 1;
145 }
146 
147 
148 /*----------------------------------------------------------------------
149       Sets up style and contents of current titlebar line
150 
151     All of the text is assumed to be UTF-8 text, which probably isn't
152     true yet.
153 
154     Args: title -- The title that appears in the center of the line
155 		     This title is in UTF-8 characters.
156           display_on_screen -- flag whether to display on screen or generate
157                                 string
158           style  -- The format/style of the titlebar line
159 	  msgmap -- MSGNO_S * to selected message map
160           current_pl -- The current page or line number
161           total_pl   -- The total line or page count
162 
163   Set the contents of the anchor line. It's called an anchor line
164 because it's always present and titlebars the user. This accesses a
165 number of global variables, but doesn't change any. There are several
166 different styles of the titlebar line.
167 
168 It's OK to call this with a bogus current message - it is only used
169 to look up status of current message
170 
171 Formats only change the right section (part3).
172   FolderName:      "<folder>"  xx Messages
173   MessageNumber:   "<folder>" message x,xxx of x,xxx XXX
174   TextPercent:     line xxx of xxx  xx%
175   MsgTextPercent:  "<folder>" message x,xxx of x,xxx  xx% XXX
176   FileTextPercent: "<filename>" line xxx of xxx  xx%
177 
178 Several strings and column numbers are saved so later updates to the status
179 line for changes in message number or percentage can be done efficiently.
180  ----*/
181 
182 char *
set_titlebar(char * title,MAILSTREAM * stream,CONTEXT_S * cntxt,char * folder,MSGNO_S * msgmap,int display_on_screen,TitleBarType style,long int current_pl,long int total_pl,COLOR_PAIR * color)183 set_titlebar(char *title, MAILSTREAM *stream, CONTEXT_S *cntxt, char *folder,
184 	     MSGNO_S *msgmap, int display_on_screen, TitleBarType style,
185 	     long int current_pl, long int total_pl, COLOR_PAIR *color)
186 {
187     struct variable *vars = ps_global->vars;
188     MESSAGECACHE  *mc = NULL;
189     PINETHRD_S    *thrd = NULL;
190     TITLE_S       *tc;
191 
192     dprint((9, "set_titlebar - style: %d  current message cnt:%ld",
193 	       style, mn_total_cur(msgmap)));
194     dprint((9, "  current_pl: %ld  total_pl: %ld\n",
195 	       current_pl, total_pl));
196 
197     as.current_msg = (mn_get_total(msgmap) > 0L)
198 			 ? MAX(0, mn_get_cur(msgmap)) : 0L;
199     as.msgmap	     = msgmap;
200     as.style	     = style;
201     as.title	     = title;
202     as.stream	     = stream;
203     as.stream_status = (!as.stream || (sp_dead_stream(as.stream)))
204 			 ? Closed : as.stream->rdonly ? OnlyRead : Normal;
205 
206     if(ps_global->first_open_was_attempted
207        && as.stream_status == Closed
208        && VAR_TITLECLOSED_FORE_COLOR && VAR_TITLECLOSED_BACK_COLOR){
209 	memset(&as.titlecontainer.color, 0, sizeof(as.titlecontainer.color));
210 	strncpy(as.titlecontainer.color.fg,
211 		VAR_TITLECLOSED_FORE_COLOR, MAXCOLORLEN);
212 	as.titlecontainer.color.fg[MAXCOLORLEN] = '\0';
213 	strncpy(as.titlecontainer.color.bg,
214 		VAR_TITLECLOSED_BACK_COLOR, MAXCOLORLEN);
215 	as.titlecontainer.color.bg[MAXCOLORLEN] = '\0';
216     }
217     else{
218 	if(color){
219 	    memset(&as.titlecontainer.color, 0, sizeof(as.titlecontainer.color));
220 	    if(color->fg){
221 		strncpy(as.titlecontainer.color.fg, color->fg, MAXCOLORLEN);
222 		as.titlecontainer.color.fg[MAXCOLORLEN] = '\0';
223 	    }
224 
225 	    if(color->bg){
226 		strncpy(as.titlecontainer.color.bg, color->bg, MAXCOLORLEN);
227 		as.titlecontainer.color.bg[MAXCOLORLEN] = '\0';
228 	    }
229 	}
230 	else{
231 	    memset(&as.titlecontainer.color, 0, sizeof(as.titlecontainer.color));
232 	    if(VAR_TITLE_FORE_COLOR){
233 		strncpy(as.titlecontainer.color.fg,
234 			VAR_TITLE_FORE_COLOR, MAXCOLORLEN);
235 		as.titlecontainer.color.fg[MAXCOLORLEN] = '\0';
236 	    }
237 
238 	    if(VAR_TITLE_BACK_COLOR){
239 		strncpy(as.titlecontainer.color.bg,
240 			VAR_TITLE_BACK_COLOR, MAXCOLORLEN);
241 		as.titlecontainer.color.bg[MAXCOLORLEN] = '\0';
242 	    }
243 	}
244     }
245 
246     if(as.folder_name)
247       fs_give((void **)&as.folder_name);
248 
249     if(folder){
250 	unsigned char *fname;
251 	fname = folder_name_decoded((unsigned char *) folder);
252 	if(!strucmp(folder, ps_global->inbox_name) && cntxt == ps_global->context_list)
253 	  as.folder_name = cpystr(pretty_fn(fname ? (char *) fname : folder));
254 	else
255 	  as.folder_name = cpystr(fname ? (char *) fname : folder);
256 	if(fname) fs_give((void **)&fname);
257     }
258 
259     if(!as.folder_name)
260       as.folder_name = cpystr("");
261 
262     if(as.context_name)
263       fs_give((void **)&as.context_name);
264 
265     /*
266      * Handle setting up the context if appropriate.
267      */
268     if(cntxt && context_isambig(folder) && ps_global->context_list->next
269        && (strucmp(as.folder_name, ps_global->inbox_name) || cntxt != ps_global->context_list)){
270 	/*
271 	 * if there's more than one context and the current folder
272 	 * is in it (ambiguous name), set the context name...
273 	 */
274 	as.context_name = cpystr(cntxt->nickname
275 				   ? cntxt->nickname
276 				   : cntxt->context);
277     }
278 
279     if(!as.context_name)
280       as.context_name = cpystr("");
281 
282     if(as.stream && style != FolderName
283        && style != ThrdIndex && as.current_msg > 0L) {
284 	long rawno;
285 
286 	if((rawno = mn_m2raw(msgmap, as.current_msg)) > 0L
287 	   && rawno <= as.stream->nmsgs
288 	   && !((mc = mail_elt(as.stream, rawno)) && mc->valid)){
289 	    pine_mail_fetch_flags(as.stream, long2string(rawno), NIL);
290 	    if(rawno <= as.stream->nmsgs && as.stream && rawno > 0L)
291 	      mc = mail_elt(as.stream, rawno);
292 	    else
293 	      mc = NULL;
294 	    if(mc && !mc->valid)
295 	      mc = NULL;
296 	}
297     }
298 
299     if(style == ThrdIndex || style == ThrdMsgNum || style == ThrdMsgPercent){
300 	if(mn_get_total(msgmap) > 0L)
301 	  thrd = fetch_thread(stream, mn_m2raw(msgmap, mn_get_cur(msgmap)));
302 
303 	if(thrd && thrd->top && thrd->top != thrd->rawno)
304 	  thrd = fetch_thread(stream, thrd->top);
305 
306 	if(thrd)
307 	  as.current_thrd = thrd->thrdno;
308     }
309 
310     switch(style) {
311       case ThrdIndex:
312 	as.total_lines = msgmap->max_thrdno;
313 	break;
314 
315       case TextPercent:
316       case MsgTextPercent:
317       case FileTextPercent :
318       case ThrdMsgPercent:
319         as.total_lines = total_pl;
320         as.current_line = current_pl;
321 				        /* fall through to set state */
322       case ThrdMsgNum:
323       case MessageNumber:
324         as.msg_state = STATUS_BITS(mc);
325 
326       case FolderName:		        /* nothing more to do for this one */
327 	break;
328       default:
329 	break;
330     }
331 
332     tc = format_titlebar();
333     if(display_on_screen)
334       output_titlebar(tc);
335 
336     return(tc->titlebar_line);
337 }
338 
339 
340 void
redraw_titlebar(void)341 redraw_titlebar(void)
342 {
343     output_titlebar(format_titlebar());
344 }
345 
346 
347 void
output_titlebar(TITLE_S * tc)348 output_titlebar(TITLE_S *tc)
349 {
350     COLOR_PAIR *lastc = NULL, *newcolor;
351 
352     if(ps_global->ttyo
353        && (ps_global->ttyo->screen_rows - FOOTER_ROWS(ps_global)) < 1){
354 	titlebar_is_dirty = 1;
355 	return;
356     }
357 
358     newcolor = tc ? &tc->color : NULL;
359 
360     if(newcolor)
361       lastc = pico_set_colorp(newcolor, PSC_REV | PSC_RET);
362 
363     if(tc && tc->titlebar_line)
364       PutLine0(0, 0, tc->titlebar_line);
365 
366     if (ps_global->ttyo)
367 	MoveCursor(0, ps_global->ttyo->screen_cols); /* move to the last column */
368 
369     if(lastc){
370 	(void)pico_set_colorp(lastc, PSC_NONE);
371 	free_color_pair(&lastc);
372     }
373 
374     fflush(stdout);
375 }
376 
377 
378 void
titlebar_stream_closing(MAILSTREAM * stream)379 titlebar_stream_closing(MAILSTREAM *stream)
380 {
381     if(stream == as.stream)
382       as.stream = NULL;
383 }
384 
385 
386 /* caller should free returned color pair */
387 COLOR_PAIR *
current_titlebar_color(void)388 current_titlebar_color(void)
389 {
390     COLOR_PAIR    *col;
391     COLOR_PAIR    *the_color = NULL;
392 
393     col = as.title ? &as.titlecontainer.color : NULL;
394 
395     if(col && col->fg && col->fg[0] && col->bg && col->bg[0])
396       the_color = new_color_pair(col->fg, col->bg);
397 
398     return(the_color);
399 }
400 
401 
402 /*----------------------------------------------------------------------
403       Redraw or draw the top line, the title bar
404 
405  The titlebar has Four fields:
406      1) "Version" of fixed length and is always positioned two spaces
407         in from left display edge.
408      2) "Location" which is fixed for each style of titlebar and
409         is positioned two spaces from the right display edge
410      3) "Title" which is of fixed length, and is centered if
411         there's space
412      4) "Folder" whose existence depends on style and which can
413         have it's length adjusted (within limits) so it will
414         equally share the space between 1) and 2) with the
415         "Title".  The rule for existence is that in the
416         space between 1) and 2) there must be one space between
417         3) and 4) AND at least 50% of 4) must be displayed.
418 	However, if the folder name can be displayed, then do
419 	so, and display as much as possible of the collection name.
420 
421    Returns - Formatted title bar
422  ----*/
423 TITLE_S *
format_titlebar(void)424 format_titlebar(void)
425 {
426     char    version[50], fold_tmp[6*MAXPATH+1], *titlebar_line,
427 	    loc1[200], loc_label[10], *thd_label, *ss_string, *q,
428 	   *plus, *loc2 = "", title[200];
429     int     title_len = 0, ver_len, loc1_len = 0, loc2_len = 0, fold_len = 0, num_len,
430 	    s1 = 0, s2 = 0, s3 = 0, s4 = 0, s5 = 0, s6 = 0, tryloc = 1,
431 	    cur_mess_col_offset = -1, percent_column_offset = -1, page_column_offset = -1,
432 	    ss_len, thd_len, is_context, avail, extra;
433 
434     titlebar_is_dirty = 0;
435 
436     if(!as.title)
437       return NULL;
438 
439     if(!as.folder_name)
440       as.folder_name = cpystr("");
441 
442     if(!as.context_name)
443       as.context_name = cpystr("");
444 
445     /*
446      * Full blown title looks like:
447      *
448      * | LV vers VT title TF folder FL location LR |
449      */
450 #define LV 2	/* space between Left edge and Version, must be >= 2 */
451 #define VT 3	/* space between Version and Title */
452 #define TF 1	/* space between Title and Folder */
453 #define FL 2	/* space between Folder and Location */
454 #define LR 2	/* space between Location and Right edge, >= 2 */
455 /* half of n but round up */
456 #define HRU(n) (((n) <= 0) ? 0 : (((n)%2) ? ((n)+1)/2 : (n)/2))
457 /* half of n but round down */
458 #define HRD(n) (((n) <= 0) ? 0 : ((n)/2))
459 
460     titlebar_line = as.titlecontainer.titlebar_line;
461 
462     avail = MIN(ps_global->ttyo->screen_cols, MAX_SCREEN_COLS);
463 
464     /* initialize */
465     as.del_column     = -1;
466     as.cur_mess_col   = -1;
467     as.percent_column = -1;
468     as.page_column    = -1;
469 
470     is_context        = as.context_name ? strlen(as.context_name) : 0;
471 
472     snprintf(version, sizeof(version), "ALPINE %s", ALPINE_VERSION);
473     version[sizeof(version)-1] = '\0';
474     ver_len = (int) utf8_width(version);	/* fixed version field width */
475 
476     title[0] = '\0';
477     if(as.title){
478 	strncpy(title, as.title, sizeof(title));
479 	title[sizeof(title)-1] = '\0';
480     }
481 
482     /* Add Sort indicator to title */
483     if(F_ON(F_SHOW_SORT, ps_global) &&
484        !(as.style == FileTextPercent || as.style == TextPercent)){
485 	SortOrder current_sort;
486 	int       current_rev;
487 	char      let;
488 
489 	current_sort = mn_get_sort(ps_global->msgmap);
490 	current_rev  = mn_get_revsort(ps_global->msgmap);
491 
492 	/* turn current_sort into a letter */
493 	let = sort_letter(current_sort);
494 	if(let == 'A' && current_rev){
495 	    let = 'R';
496 	    current_rev = 0;
497 	}
498 
499 	snprintf(title+strlen(title), sizeof(title)-strlen(title),
500 		 " [%s%c]", current_rev ? "R" : "", let);
501 	title[sizeof(title)-1] = '\0';
502     }
503 
504     title_len = (int) utf8_width(title);	/* title field width   */
505 
506     s1 = MAX(MIN(LV, avail), 0);	/* left two spaces */
507     avail -= s1;
508 
509     s6 = MAX(MIN(LR, avail), 0);	/* right two spaces */
510     avail -= s6;
511 
512     title_len = MAX(MIN(title_len, avail), 0);
513     avail -= title_len;
514 
515     if(ver_len + VT > avail){		/* can only fit title */
516 	ver_len = 0;
517 
518 	s2 = MAX(MIN(HRD(avail), avail), 0);
519 	avail -= s2;
520 
521 	s3 = MAX(0, avail);
522     }
523     else{
524 	s2 = MAX(MIN(VT, avail), 0);
525 	avail -= s2;
526 
527 	ver_len = MAX(MIN(ver_len, avail), 0);
528 	avail -= ver_len;
529 
530 try_smaller_loc:
531 
532 	/*
533 	 * set location field's length and value based on requested style
534 	 */
535 	if(as.style == ThrdIndex)
536 	  /* TRANSLATORS: In titlebar, Thd is an abbreviation for Thread, Msg for Message.
537 	     They are used when there isn't enough space so need to be short.
538 	     The formatting isn't very flexible. These come before the number
539 	     of the message or thread, as in
540 	     Message 17
541 	     when reading message number 17. */
542 	  snprintf(loc_label, sizeof(loc_label), "%s ", (is_context || tryloc==2) ? _("Thd") : _("Thread"));
543 	else
544 	  snprintf(loc_label, sizeof(loc_label), "%s ", (is_context || tryloc==2) ? _("Msg") : _("Message"));
545 
546 	if(tryloc == 3 && as.style != FolderName && mn_get_total(as.msgmap))
547 	  loc_label[0] = '\0';
548 
549 	loc_label[sizeof(loc_label)-1] = '\0';
550 
551 	if(as.style == ThrdMsgNum || as.style == ThrdMsgPercent){
552 	    thd_label = is_context ? _("Thd") : _("Thread");
553 	    thd_len = (int) utf8_width(thd_label);
554 	}
555 
556 	loc1_len = (int) utf8_width(loc_label);		/* initial length */
557 
558 	if(!mn_get_total(as.msgmap)){
559 	    loc_label[strlen(loc_label)-1] = 's';
560 	    snprintf(loc1, sizeof(loc1), "%s %s", _("No"), loc_label);
561 	    loc1[sizeof(loc1)-1]= '\0';
562 	}
563 	else{
564 	    switch(as.style){
565 	      case FolderName :			/* "x,xxx <loc_label>s" */
566 		if(*loc_label){
567 		    if(mn_get_total(as.msgmap) != 1)
568 		      loc_label[strlen(loc_label)-1] = 's';
569 		    else
570 		      loc_label[strlen(loc_label)-1] = '\0';
571 		}
572 
573 		snprintf(loc1, sizeof(loc1), "%s %s", comatose(mn_get_total(as.msgmap)), loc_label);
574 		loc1[sizeof(loc1)-1]= '\0';
575 		break;
576 
577 	      case MessageNumber :	       	/* "<loc_label> xxx of xxx DEL"  */
578 		num_len = strlen(comatose(mn_get_total(as.msgmap)));
579 		cur_mess_col_offset = loc1_len;
580 		snprintf(loc1, sizeof(loc1), "%s%*.*s of %s", loc_label,
581 			num_len, num_len,
582 			comatose(as.current_msg),
583 			comatose(mn_get_total(as.msgmap)));
584 		loc1[sizeof(loc1)-1]= '\0';
585 		loc2 = BAR_STATUS(as.msg_state);
586 		loc2_len = 3;
587 		break;
588 
589 	      case ThrdIndex :	       	/* "<loc_label> xxx of xxx"  */
590 		num_len = strlen(comatose(as.total_lines));
591 		cur_mess_col_offset = loc1_len;
592 		snprintf(loc1, sizeof(loc1), "%s%*.*s of %s", loc_label,
593 			num_len, num_len,
594 			comatose(as.current_thrd),
595 			comatose(as.total_lines));
596 		loc1[sizeof(loc1)-1]= '\0';
597 		break;
598 
599 	      case ThrdMsgNum :	       	/* "<loc_label> xxx in Thd xxx DEL"  */
600 		num_len = strlen(comatose(mn_get_total(as.msgmap)));
601 		cur_mess_col_offset = loc1_len;
602 		snprintf(loc1, sizeof(loc1), "%s%*.*s in %s %s", loc_label,
603 			num_len, num_len,
604 			comatose(as.current_msg),
605 			thd_label,
606 			comatose(as.current_thrd));
607 		loc1[sizeof(loc1)-1]= '\0';
608 		loc2 = BAR_STATUS(as.msg_state);
609 		loc2_len = 3;
610 		break;
611 
612 	      case MsgTextPercent :		/* "<loc_label> xxx of xxx xx% DEL" */
613 		num_len = strlen(comatose(mn_get_total(as.msgmap)));
614 		cur_mess_col_offset = loc1_len;
615 		percent_column_offset = 3;
616 		snprintf(loc1, sizeof(loc1), "%s%*.*s of %s %s", loc_label,
617 			num_len, num_len,
618 			comatose(as.current_msg),
619 			comatose(mn_get_total(as.msgmap)),
620 			percentage(as.current_line, as.total_lines, 1));
621 		loc1[sizeof(loc1)-1]= '\0';
622 		loc2 = BAR_STATUS(as.msg_state);
623 		loc2_len = 3;
624 		break;
625 
626 	      case ThrdMsgPercent :	  /* "<loc_label> xxx in Thd xxx xx% DEL"  */
627 		num_len = strlen(comatose(mn_get_total(as.msgmap)));
628 		cur_mess_col_offset = loc1_len;
629 		percent_column_offset = 3;
630 		snprintf(loc1, sizeof(loc1), "%s%*.*s in %s %s %s", loc_label,
631 			num_len, num_len,
632 			comatose(as.current_msg),
633 			thd_label,
634 			comatose(as.current_thrd),
635 			percentage(as.current_line, as.total_lines, 1));
636 		loc1[sizeof(loc1)-1]= '\0';
637 		loc2 = BAR_STATUS(as.msg_state);
638 		loc2_len = 3;
639 		break;
640 
641 	      case TextPercent :
642 		/* NOTE: no fold_tmp setup below for TextPercent style */
643 	      case FileTextPercent :	/* "Line xxx of xxx xx%" */
644 		num_len = strlen(comatose(as.total_lines));
645 		page_column_offset = 5;
646 		percent_column_offset = 3;
647 		snprintf(loc1, sizeof(loc1), "Line %*.*s of %s %s",
648 			num_len, num_len,
649 			comatose(as.current_line),
650 			comatose(as.total_lines),
651 			percentage(as.current_line, as.total_lines, 1));
652 		loc1[sizeof(loc1)-1]= '\0';
653 		break;
654 	      default:
655 		break;
656 	    }
657 	}
658 
659 	loc1_len = utf8_width(loc1);
660 
661 	if(loc1_len + loc2_len + ((loc2_len > 0) ? 1 : 0) >= avail){		/* can't fit location in */
662 	    if(tryloc < 3){
663 		tryloc++;
664 		goto try_smaller_loc;
665 	    }
666 
667 	    loc1_len = loc2_len = 0;
668 
669 	    avail += s2;			/* re-allocate s2 to center title */
670 
671 	    s2 = MAX(MIN(HRD(avail), avail), 0);
672 	    avail -= s2;
673 
674 	    s3 = MAX(0, avail);
675 	}
676 	else{
677 	    loc1_len = MAX(MIN(loc1_len, avail), 0);
678 	    avail -= loc1_len;
679 
680 	    loc2_len = MAX(MIN(loc2_len, avail), 0);
681 	    avail -= loc2_len;
682 
683 	    if(loc2_len > 0){
684 		s5 = MAX(MIN(1, avail), 0);
685 		avail -= s5;
686 	    }
687 	    else
688 	      s5 = 0;
689 
690 	    s3 = MAX(MIN(TF, avail), 0);
691 	    avail -= s3;
692 
693 	    s4 = MAX(MIN(FL, avail), 0);
694 	    avail -= s4;
695 
696 	    if(avail){
697 		/* TRANSLATORS: it might say READONLY or CLOSED in the titlebar, referring to
698 		   the current folder. */
699 		ss_string         = as.stream_status == Closed ? _("(CLOSED)") :
700 				    (as.stream_status == OnlyRead
701 				     && !IS_NEWS(as.stream))
702 				       ? _("(READONLY)") : "";
703 		ss_len            = (int) utf8_width(ss_string);
704 
705 		/* figure folder_length and what's to be displayed */
706 		fold_tmp[0] = '\0';
707 		if(as.style == FileTextPercent || as.style == TextPercent){
708 		    if(as.style == FileTextPercent){
709 			extra    = (int) utf8_width("File: ");
710 			fold_len = (int) utf8_width(as.folder_name);
711 			if(fold_len + extra <= avail){ 	/* all of folder fit? */
712 			    strncpy(fold_tmp, "File: ", sizeof(fold_tmp));
713 			    q = fold_tmp + strlen(fold_tmp);
714 			    strncpy(q, as.folder_name, sizeof(fold_tmp)-(q-fold_tmp));
715 			}
716 			else if(HRU(fold_len) + extra+3 <= avail){
717 			    /*
718 			     * fold_tmp = ...partial_folder_name
719 			     */
720 			    strncpy(fold_tmp, "File: ...", sizeof(fold_tmp));
721 			    q = fold_tmp + strlen(fold_tmp);
722 			    (void) utf8_to_width_rhs(q, as.folder_name, sizeof(fold_tmp)-(q-fold_tmp), avail-(extra+3));
723 			}
724 		    }
725 		    /* else leave folder/file name blank */
726 		}
727 		else{
728 		    int    ct_len;
729 
730 		    fold_len = (int) utf8_width(as.folder_name);
731 
732 		    if(is_context
733 		      && as.stream_status != Closed
734 		      && (ct_len = (int) utf8_width(as.context_name))){
735 
736 			extra = 3;		/* length from "<" ">" and SPACE */
737 
738 			if(ct_len + fold_len + ss_len + extra <= avail){
739 			    q = fold_tmp;
740 			    *q++ = '<';
741 			    strncpy(q, as.context_name, sizeof(fold_tmp)-(q-fold_tmp));
742 			    q += strlen(q);
743 			    *q++ = '>';
744 			    *q++ = ' ';
745 			    strncpy(q, as.folder_name, sizeof(fold_tmp)-(q-fold_tmp));
746 			    q += strlen(q);
747 			    strncpy(q, ss_string, sizeof(fold_tmp)-(q-fold_tmp));
748 			}
749 			else if(ct_len + fold_len + ss_len + extra <= avail){
750 			    q = fold_tmp;
751 			    *q++ = '<';
752 			    strncpy(q, as.context_name, sizeof(fold_tmp)-(q-fold_tmp));
753 			    q += strlen(q);
754 			    *q++ = '>';
755 			    *q++ = ' ';
756 			    strncpy(q, as.folder_name, sizeof(fold_tmp)-(q-fold_tmp));
757 			    q += strlen(q);
758 			    strncpy(q, ss_string, sizeof(fold_tmp)-(q-fold_tmp));
759 			}
760 			else if(HRU(ct_len) + fold_len + ss_len + extra <= avail){
761 			    q = fold_tmp;
762 			    *q++ = '<';
763 			    q += utf8_pad_to_width(q, as.context_name, sizeof(fold_tmp)-(q-fold_tmp), avail-(fold_len+ss_len+extra), 1);
764 			    *q++ = '>';
765 			    *q++ = ' ';
766 			    strncpy(q, as.folder_name, sizeof(fold_tmp)-(q-fold_tmp));
767 			    q += strlen(q);
768 			    strncpy(q, ss_string, sizeof(fold_tmp)-(q-fold_tmp));
769 			}
770 			else if(HRU(ct_len) + HRU(fold_len) + ss_len + extra <= avail){
771 			    q = fold_tmp;
772 			    *q++ = '<';
773 			    q += utf8_pad_to_width(q, as.context_name, sizeof(fold_tmp)-(q-fold_tmp), HRU(ct_len), 1);
774 			    *q++ = '>';
775 			    *q++ = ' ';
776 			    q += utf8_to_width_rhs(q, as.folder_name, sizeof(fold_tmp)-(q-fold_tmp), avail-(HRU(ct_len)+ss_len+extra));
777 			    strncpy(q, ss_string, sizeof(fold_tmp)-(q-fold_tmp));
778 			}
779 			else if(ss_len > 0 && ss_len <= avail){
780 			    q = fold_tmp;
781 			    strncpy(q, ss_string, sizeof(fold_tmp)-(q-fold_tmp));
782 			} else if(fold_len < avail){
783 			    q = fold_tmp;
784 			    if(fold_len + 7 < avail){
785 			       *q++ = '<';
786 			       q += utf8_pad_to_width(q, as.context_name, sizeof(fold_tmp)-(q-fold_tmp), avail - fold_len - 3, 1);
787 			       *q++ = '>';
788 			       *q++ = ' ';
789 			    }
790 			    strncpy(q, as.folder_name, sizeof(fold_tmp)-(q-fold_tmp));
791 			}
792 			/* else leave it out */
793 		    }
794 		    else{
795 			/* TRANSLATORS: the name of the open folder follows this in the titlebar */
796 			extra = strlen(_("Folder: "));
797 			if(fold_len + ss_len + extra <= avail){
798 			    q = fold_tmp;
799 			    strncpy(q, "Folder: ", sizeof(fold_tmp)-(q-fold_tmp));
800 			    q += strlen(q);
801 			    strncpy(q, as.folder_name, sizeof(fold_tmp)-(q-fold_tmp));
802 			    q += strlen(q);
803 			    strncpy(q, ss_string, sizeof(fold_tmp)-(q-fold_tmp));
804 			}
805 			else{
806 			    if(fold_len + ss_len <= avail){
807 				q = fold_tmp;
808 				strncpy(q, as.folder_name, sizeof(fold_tmp)-(q-fold_tmp));
809 				q += strlen(q);
810 				strncpy(q, ss_string, sizeof(fold_tmp)-(q-fold_tmp));
811 			    }
812 			    else if(((HRU(fold_len) + ss_len <= avail)
813 				     || (avail > ss_len+3 && avail > 10)) && fold_len > 5){
814 				q = fold_tmp;
815 				strncpy(q, "...", sizeof(fold_tmp));
816 				q += strlen(q);
817 				q += utf8_to_width_rhs(q, as.folder_name, sizeof(fold_tmp)-(q-fold_tmp), avail-(3+ss_len));
818 				strncpy(q, ss_string, sizeof(fold_tmp)-(q-fold_tmp));
819 			    }
820 			    else if(ss_len > 0 && ss_len <= avail){
821 				q = fold_tmp;
822 				strncpy(q, ss_string, sizeof(fold_tmp)-(q-fold_tmp));
823 			    }
824 			    /* else leave it out */
825 			}
826 		    }
827 		}
828 
829 		fold_tmp[sizeof(fold_tmp)-1] = '\0';
830 
831 		/* write title, location and, optionally, the folder name */
832 		fold_len = (int) utf8_width(fold_tmp);
833 	    }
834 
835 	    fold_len = MAX(MIN(fold_len, avail), 0);
836 	    avail -= fold_len;
837 
838 	    /* center folder in its space */
839 	    if(avail){
840 		int inc;
841 
842 		inc = HRU(avail);
843 
844 		s3 += inc;
845 		avail -= inc;
846 
847 		s4 += avail;
848 	    }
849 	}
850     }
851 
852     plus = "";
853 
854     if(as.style != FileTextPercent && as.style != TextPercent){
855 	NETMBX mb;
856 
857 	if(as.stream
858 	   && as.stream->mailbox
859 	   && mail_valid_net_parse(as.stream->mailbox, &mb)
860 	   && (mb.sslflag || mb.tlsflag))
861 	  plus = "+";
862     }
863 
864 
865     if(loc1_len > 0 && cur_mess_col_offset >= 0)
866       as.cur_mess_col = s1+ver_len+s2+title_len+s3+fold_len+s4 + cur_mess_col_offset;
867 
868     if(loc1_len > 0 && page_column_offset >= 0)
869       as.page_column = s1+ver_len+s2+title_len+s3+fold_len+s4 + page_column_offset;
870 
871     if(loc2_len > 0)
872       as.del_column = s1+ver_len+s2+title_len+s3+fold_len+s4+loc1_len+s5;
873 
874     if(loc1_len > 0 && percent_column_offset > 0)
875       as.percent_column = s1+ver_len+s2+title_len+s3+fold_len+s4+loc1_len - percent_column_offset;
876 
877 
878     utf8_snprintf(titlebar_line, 6*MAX_SCREEN_COLS, "%*.*s%-*.*w%*.*s%-*.*w%*.*s%-*.*w%*.*s%-*.*w%*.*s%-*.*w%*.*s",
879 		  s1, s1, "",
880 		  ver_len, ver_len, version,
881 		  s2, s2, "",
882 		  title_len, title_len, title,
883 		  s3, s3, "",
884 		  fold_len, fold_len, fold_tmp,
885 		  s4, s4, "",
886 		  loc1_len, loc1_len, loc1,
887 		  s5, s5, "",
888 		  loc2_len, loc2_len, loc2,
889 		  s6, s6, plus);
890 
891     return(&as.titlecontainer);
892 }
893 
894 
895 char
sort_letter(SortOrder sort)896 sort_letter(SortOrder sort)
897 {
898     char let = 'A', *p;
899 
900     if((p = sort_name(sort)) != NULL && *p){
901 	while(*(p+1) && islower((unsigned char) *p))
902 	  p++;
903 
904 	if(*p)
905 	  let = *p;
906     }
907 
908     return(let);
909 }
910 
911 
912 /*
913  *  Update the titlebar line if the message number changed
914  *
915  *  Args: None, uses state setup on previous call to set_titlebar.
916  */
917 void
update_titlebar_message(void)918 update_titlebar_message(void)
919 {
920     long        curnum = 0, maxnum, oldnum = 0;
921     PINETHRD_S *thrd = NULL;
922     COLOR_PAIR *lastc = NULL, *titlecolor;
923     char        buf[50];
924     int         num_len;
925     unsigned long rawno;
926 
927     if(ps_global->ttyo
928        && (ps_global->ttyo->screen_rows - FOOTER_ROWS(ps_global)) < 1){
929 	titlebar_is_dirty = 1;
930 	return;
931     }
932 
933     if(as.style == ThrdIndex){
934 
935 	oldnum = as.current_thrd;
936 
937 	if(as.stream && (rawno=mn_m2raw(as.msgmap, mn_get_cur(as.msgmap))))
938 	  thrd = fetch_thread(as.stream, rawno);
939 
940 	if(thrd && thrd->top && (thrd=fetch_thread(as.stream, thrd->top)))
941 	  curnum = thrd->thrdno;
942     }
943     else if(as.cur_mess_col >= 0){
944 	curnum = mn_get_cur(as.msgmap);
945 	oldnum = as.current_msg;
946     }
947 
948     if(as.cur_mess_col >= 0 && oldnum != curnum){
949 
950 	if(as.style == ThrdIndex){
951 	    as.current_thrd = curnum;
952 	    maxnum = as.msgmap->max_thrdno;
953 	}
954 	else{
955 	    as.current_msg = curnum;
956 	    maxnum = mn_get_total(as.msgmap);
957 	}
958 
959 	titlecolor = &as.titlecontainer.color;
960 
961 	if(titlecolor)
962 	  lastc = pico_set_colorp(titlecolor, PSC_REV|PSC_RET);
963 
964 	num_len = strlen(comatose(maxnum));
965 
966 	snprintf(buf, sizeof(buf), "%*.*s", num_len, num_len, comatose(curnum));
967 
968 	PutLine0(0, as.cur_mess_col, buf);
969 
970 	if (ps_global->ttyo)
971 	    MoveCursor(0, ps_global->ttyo->screen_cols); /* move to the last column */
972 
973 	if(lastc){
974 	    (void)pico_set_colorp(lastc, PSC_NONE);
975 	    free_color_pair(&lastc);
976 	}
977 
978 	fflush(stdout);
979     }
980 }
981 
982 
983 
984 /*
985  *  Update titlebar line's message status field ("DEL", "NEW", etc)
986  *
987  *  Args:  None, operates on state set during most recent set_titlebar call
988  */
989 int
update_titlebar_status(void)990 update_titlebar_status(void)
991 {
992     unsigned long rawno;
993     MESSAGECACHE *mc;
994     COLOR_PAIR *lastc = NULL, *titlecolor;
995 
996     if(ps_global->ttyo
997        && (ps_global->ttyo->screen_rows - FOOTER_ROWS(ps_global)) < 1){
998 	titlebar_is_dirty = 1;
999 	return(0);
1000     }
1001 
1002     if(!as.stream || as.current_msg <= 0L || as.del_column < 0)
1003       return(1);
1004 
1005     if(as.current_msg != mn_get_cur(as.msgmap))
1006       update_titlebar_message();
1007 
1008     mc = ((rawno = mn_m2raw(as.msgmap, as.current_msg)) > 0L
1009 	  && rawno <= as.stream->nmsgs)
1010 	    ? mail_elt(as.stream, rawno) : NULL;
1011 
1012     if(!(mc && mc->valid))
1013       return(0);			/* indeterminate */
1014 
1015     if(mc->deleted){			/* deleted takes precedence */
1016 	if(as.msg_state & MS_DEL)
1017 	  return(1);
1018     }
1019     else if(mc->answered){		/* then answered */
1020 	if(as.msg_state & MS_ANS)
1021 	  return(1);
1022     }					/* then forwarded */
1023     else if(user_flag_is_set(as.stream, mc->msgno, FORWARDED_FLAG)){
1024 	if(as.msg_state & MS_FWD)
1025 	  return(1);
1026     }
1027     else if(!mc->seen && as.stream
1028 	    && (!IS_NEWS(as.stream)
1029 		|| F_ON(F_FAKE_NEW_IN_NEWS, ps_global))){
1030 	if(as.msg_state & MS_NEW)	/* then seen */
1031 	  return(1);
1032     }
1033     else{
1034 	if(as.msg_state == 0)		/* nothing to change */
1035 	  return(1);
1036     }
1037 
1038     as.msg_state = STATUS_BITS(mc);
1039 
1040     titlecolor = &as.titlecontainer.color;
1041 
1042     if(titlecolor)
1043       lastc = pico_set_colorp(titlecolor, PSC_REV|PSC_RET);
1044 
1045     PutLine0(0, as.del_column, BAR_STATUS(as.msg_state));
1046 
1047     if (ps_global->ttyo)
1048 	MoveCursor(0, ps_global->ttyo->screen_cols); /* move to the last column */
1049 
1050     if(lastc){
1051 	(void)pico_set_colorp(lastc, PSC_NONE);
1052 	free_color_pair(&lastc);
1053     }
1054 
1055     fflush(stdout);
1056     return(1);
1057 }
1058 
1059 
1060 /*
1061  *  Update the percentage shown in the titlebar line
1062  *
1063  *  Args: new_line_number -- line number to calculate new percentage
1064  */
1065 void
update_titlebar_percent(long int new_line_number)1066 update_titlebar_percent(long int new_line_number)
1067 {
1068     COLOR_PAIR *lastc = NULL, *titlecolor;
1069 
1070     if(as.percent_column < 0 || new_line_number == as.current_line)
1071       return;
1072 
1073     if(ps_global->ttyo
1074        && (ps_global->ttyo->screen_rows - FOOTER_ROWS(ps_global)) < 1){
1075 	titlebar_is_dirty = 1;
1076 	return;
1077     }
1078 
1079     as.current_line = new_line_number;
1080 
1081     titlecolor = &as.titlecontainer.color;
1082 
1083     if(titlecolor)
1084       lastc = pico_set_colorp(titlecolor, PSC_REV|PSC_RET);
1085 
1086     PutLine0(0, as.percent_column,
1087 	     percentage(as.current_line, as.total_lines, 0));
1088 
1089     if (ps_global->ttyo)
1090 	MoveCursor(0, ps_global->ttyo->screen_cols); /* move to the last column */
1091 
1092     if(lastc){
1093 	(void)pico_set_colorp(lastc, PSC_NONE);
1094 	free_color_pair(&lastc);
1095     }
1096 
1097     fflush(stdout);
1098 }
1099 
1100 
1101 /*
1102  *  Update the percentage AND line number shown in the titlebar line
1103  *
1104  *  Args: new_line_number -- line number to calculate new percentage
1105  */
1106 void
update_titlebar_lpercent(long int new_line_number)1107 update_titlebar_lpercent(long int new_line_number)
1108 {
1109     COLOR_PAIR *lastc = NULL, *titlecolor;
1110     int         num_len;
1111     char        buf[50];
1112 
1113     if(as.page_column < 0 || new_line_number == as.current_line)
1114       return;
1115 
1116     if(ps_global->ttyo
1117        && (ps_global->ttyo->screen_rows - FOOTER_ROWS(ps_global)) < 1){
1118 	titlebar_is_dirty = 1;
1119 	return;
1120     }
1121 
1122     as.current_line = new_line_number;
1123 
1124     titlecolor = &as.titlecontainer.color;
1125 
1126     if(titlecolor)
1127       lastc = pico_set_colorp(titlecolor, PSC_REV|PSC_RET);
1128 
1129     num_len = strlen(comatose(as.total_lines));
1130     snprintf(buf, sizeof(buf), "%*.*s", num_len, num_len, comatose(as.current_line));
1131 
1132     PutLine0(0, as.page_column, buf);
1133 
1134     PutLine0(0, as.percent_column,
1135 	     percentage(as.current_line, as.total_lines, 0));
1136 
1137     if (ps_global->ttyo)
1138 	MoveCursor(0, ps_global->ttyo->screen_cols); /* move to the last column */
1139 
1140     if(lastc){
1141 	(void)pico_set_colorp(lastc, PSC_NONE);
1142 	free_color_pair(&lastc);
1143     }
1144 
1145     fflush(stdout);
1146 }
1147 
1148 
1149 /*----------------------------------------------------------------------
1150     Return static buf containing portion of lines displayed
1151 
1152   Args:  part -- how much so far
1153 	 total -- how many total
1154 
1155   ---*/
1156 char *
percentage(long int part,long int total,int suppress_top)1157 percentage(long int part, long int total, int suppress_top)
1158 {
1159     static char percent[4];
1160 
1161     if(total == 0L || (total <= ps_global->ttyo->screen_rows
1162 				 - HEADER_ROWS(ps_global)
1163 				 - FOOTER_ROWS(ps_global)))
1164       strncpy(percent, "ALL", sizeof(percent));
1165     else if(!suppress_top && part <= ps_global->ttyo->screen_rows
1166 				      - HEADER_ROWS(ps_global)
1167 				      - FOOTER_ROWS(ps_global))
1168       strncpy(percent, "TOP", sizeof(percent));
1169     else if(part >= total)
1170       strncpy(percent, "END", sizeof(percent));
1171     else
1172       snprintf(percent, sizeof(percent), "%2ld%%", (100L * part)/total);
1173 
1174     percent[sizeof(percent)-1] = '\0';
1175 
1176     return(percent);
1177 }
1178 
1179 
1180 /*
1181  * end_titlebar - free resources associated with titlebar state struct
1182  */
1183 void
end_titlebar(void)1184 end_titlebar(void)
1185 {
1186     if(as.folder_name)
1187       fs_give((void **)&as.folder_name);
1188 
1189     if(as.context_name)
1190       fs_give((void **)&as.context_name);
1191 }
1192 
1193 
1194 /*----------------------------------------------------------------------
1195    Exported method to display status of mail check
1196 
1197    Args: putstr -- should be NO LONGER THAN 2 bytes
1198 
1199  Result: putstr displayed at upper-left-hand corner of screen
1200   ----*/
1201 void
check_cue_display(char * putstr)1202 check_cue_display(char *putstr)
1203 {
1204     COLOR_PAIR *lastc = NULL, *titlecolor;
1205     static char check_cue_char;
1206 
1207     if(ps_global->read_predicted &&
1208        (check_cue_char == putstr[0]
1209 	|| (putstr[0] == ' ' && putstr[1] == '\0')))
1210         return;
1211     else{
1212         if(putstr[0] == ' ')
1213 	  check_cue_char = '\0';
1214 	else
1215 	  check_cue_char = putstr[0];
1216     }
1217 
1218     titlecolor = &as.titlecontainer.color;
1219 
1220     if(titlecolor)
1221       lastc = pico_set_colorp(titlecolor, PSC_REV|PSC_RET);
1222 
1223     PutLine0(0, 0, putstr);		/* show delay cue */
1224 
1225     if (ps_global->ttyo)
1226 	MoveCursor(0, ps_global->ttyo->screen_cols); /* move to the last column */
1227 
1228     if(lastc){
1229 	(void)pico_set_colorp(lastc, PSC_NONE);
1230 	free_color_pair(&lastc);
1231     }
1232 
1233     fflush(stdout);
1234 }
1235 
1236 
1237 /*----------------------------------------------------------------------
1238    Mandatory function of ../pith/newmail.c
1239 
1240    Args: none
1241 
1242  Result: newmail cue displayed at upper-left-hand corner of screen
1243   ----*/
1244 void
newmail_check_cue(int onoroff)1245 newmail_check_cue(int onoroff)
1246 {
1247     if(F_ON(F_SHOW_DELAY_CUE, ps_global) && !ps_global->in_init_seq){
1248 	check_cue_display((onoroff == TRUE) ? " *" : "  ");
1249 	MoveCursor(ps_global->ttyo->screen_rows-FOOTER_ROWS(ps_global), 0);
1250     }
1251 
1252 #ifdef _WINDOWS
1253     if(onoroff)
1254       mswin_setcursor (MSWIN_CURSOR_BUSY);
1255     else
1256       mswin_setcursor (MSWIN_CURSOR_ARROW);
1257 #endif
1258 }
1259 
1260 
1261 /*----------------------------------------------------------------------
1262    Mandatory function of ../pith/newmail.c
1263 
1264    Args: none
1265 
1266  Result: checkpoint delay cue displayed at upper-left-hand corner of screen
1267   ----*/
1268 void
newmail_check_point_cue(int onoroff)1269 newmail_check_point_cue(int onoroff)
1270 {
1271     if(F_ON(F_SHOW_DELAY_CUE, ps_global)){
1272 	check_cue_display((onoroff == TRUE) ? "**" : "  ");
1273 	MoveCursor(ps_global->ttyo->screen_rows-FOOTER_ROWS(ps_global), 0);
1274     }
1275 
1276 #ifdef _WINDOWS
1277     if(onoroff)
1278       mswin_setcursor (MSWIN_CURSOR_BUSY);
1279     else
1280       mswin_setcursor (MSWIN_CURSOR_ARROW);
1281 #endif
1282 }
1283 
1284 void
free_titlebar_globals(void)1285 free_titlebar_globals(void)
1286 {
1287   if(as_fname) fs_give((void **) &as_fname);
1288   if(as_cname) fs_give((void **) &as_cname);
1289   if(as.folder_name) fs_give((void **)&as.folder_name);
1290   if(as.context_name) fs_give((void **)&as.context_name);
1291 }
1292