2 * Copyright notice from original mutt:
3 * Copyright (C) ????-2004 Justin Hibbits <jrh29@po.cwru.edu>
4 * Copyright (C) 2004 Thomer M. Gil <mutt@thomer.com>
6 * Parts were written/modified by:
7 * Rocco Rutte <pdmef@cs.tu-berlin.de>
8 * Nico Golde <nico@ngolde.de>
10 * This file is part of mutt-ng, see http://www.muttng.org/.
11 * It's licensed under the GNU General Public License,
12 * please see the file GPL in the top level source directory.
15 #include <lib-lib/mem.h>
16 #include <lib-lib/str.h>
17 #include <lib-lib/macros.h>
19 #include <lib-ui/curses.h>
20 #include <lib-ui/menu.h>
31 static int TopBuffy = 0;
32 static int CurBuffy = 0;
33 static int known_lines = 0;
34 static short initialized = 0;
35 static short prev_show_value;
37 /* computes first entry to be shown */
38 static void calc_boundaries (void) {
39 if (list_empty(Incoming))
41 if (CurBuffy < 0 || CurBuffy >= Incoming->length)
43 if (TopBuffy < 0 || TopBuffy >= Incoming->length)
46 if (option (OPTSIDEBARNEWMAILONLY)) {
48 TopBuffy = CurBuffy - 1;
50 if (((BUFFY*) Incoming->data[i])->new > 0)
54 } else if (known_lines>0)
55 TopBuffy = CurBuffy - (CurBuffy % known_lines);
60 static char *shortened_hierarchy (char *box, int maxlen)
63 char *last_dot = NULL;
64 int i, j, len = m_strlen(box);
67 if (!SidebarBoundary || !*SidebarBoundary)
68 return (m_strdup(box));
70 for (i = 0; i < len; ++i) {
71 if (strchr (SidebarBoundary, box[i])) {
79 new_box = p_new(char, maxlen + 1);
81 for (i = 1, j = 1; j < maxlen && i < len; ++i) {
82 if (strchr (SidebarBoundary, box[i])) {
83 new_box[j++] = box[i];
85 if (&box[i + 1] != last_dot || j + m_strlen(last_dot) > maxlen) {
86 new_box[j++] = box[i + 1];
89 strcat (&new_box[j], last_dot);
99 static const char* sidebar_number_format (char* dest, size_t destlen, char op,
100 const char* src, const char* fmt,
101 const char* ifstr, const char* elstr,
102 unsigned long data, format_flag flags) {
103 char tmp[SHORT_STRING];
104 BUFFY* b = (BUFFY*) Incoming->data[data];
105 int opt = flags & M_FORMAT_OPTIONAL;
106 int c = Context && !m_strcmp(Context->path, b->path);
112 snprintf (tmp, sizeof (tmp), "%%%sd", fmt);
113 snprintf (dest, destlen, tmp, c ? Context->deleted : 0);
114 } else if ((c && Context->deleted == 0) || !c)
119 case 'f': /* for compatibility */
121 snprintf (tmp, sizeof (tmp), "%%%sd", fmt);
122 snprintf (dest, destlen, tmp, c ? Context->flagged : b->msg_flagged);
123 } else if ((c && Context->flagged == 0) || (!c && b->msg_flagged == 0))
127 case 'c': /* for compatibility */
130 snprintf (tmp, sizeof (tmp), "%%%sd", fmt);
131 snprintf (dest, destlen, tmp, c ? Context->msgcount : b->msgcount);
132 } else if ((c && Context->msgcount == 0) || (!c && b->msgcount == 0))
135 /* total shown, i.e. not hidden by limit */
138 snprintf (tmp, sizeof (tmp), "%%%sd", fmt);
139 snprintf (dest, destlen, tmp, c ? Context->vcount : 0);
140 } else if ((c && Context->vcount == 0) || !c)
146 snprintf (tmp, sizeof (tmp), "%%%sd", fmt);
147 snprintf (dest, destlen, tmp, c ? Context->new : b->new);
148 } else if ((c && Context->new == 0) || (!c && b->new == 0))
154 snprintf (tmp, sizeof (tmp), "%%%sd", fmt);
155 snprintf (dest, destlen, tmp, c ? Context->unread : b->msg_unread);
156 } else if ((c && Context->unread == 0) || (!c && b->msg_unread == 0))
162 snprintf (tmp, sizeof (tmp), "%%%sd", fmt);
163 snprintf (dest, destlen, tmp, c ? Context->tagged : 0);
164 } else if ((c && Context->tagged == 0) || !c)
170 mutt_FormatString (dest, destlen, ifstr, sidebar_number_format,
171 data, M_FORMAT_OPTIONAL);
172 else if (flags & M_FORMAT_OPTIONAL)
173 mutt_FormatString (dest, destlen, elstr, sidebar_number_format,
174 data, M_FORMAT_OPTIONAL);
178 int sidebar_need_count (void) {
179 if (!option (OPTMBOXPANE) || SidebarWidth == 0 ||
180 !SidebarNumberFormat || !*SidebarNumberFormat)
187 * 0 item was not printed ('cause of $sidebar_newmail_only)
190 int make_sidebar_entry (char* box, int idx, size_t len)
192 int shortened = 0, lencnt = 0;
193 char no[SHORT_STRING], entry[SHORT_STRING];
194 int l = m_strlen(ImapHomeNamespace);
195 int l_m = m_strlen(Maildir);
197 if (SidebarWidth > COLS)
200 if (option (OPTSIDEBARNEWMAILONLY) && box && Context && Context->path &&
201 m_strcmp(Context->path, box) && ((BUFFY*) Incoming->data[idx])->new == 0)
202 /* if $sidebar_newmail_only is set, don't display the
203 * box only if it's not the currently opened
204 * (i.e. always display the currently opened) */
207 mutt_FormatString (no, len, NONULL (SidebarNumberFormat),
208 sidebar_number_format, idx, M_FORMAT_OPTIONAL);
209 lencnt = m_strlen(no);
210 memset(&entry, ' ', sizeof(entry));
212 if (l > 0 && m_strncmp(box, ImapHomeNamespace, l) == 0 &&
214 box += l + 1; /* we're trimming the ImapHomeNamespace, the "+ 1" is for the separator */
216 if (l_m > 0 && m_strncmp(box, Maildir, l_m) == 0 &&
217 m_strlen(box) > l_m) {
219 if (Maildir[strlen(Maildir)-1]!='/') {
223 box = basename (box);
225 if (option (OPTSHORTENHIERARCHY) && m_strlen(box) > len-lencnt-1) {
226 box = shortened_hierarchy (box, len-lencnt-1);
230 m_strcpy(entry, len - lencnt, box);
231 entry[m_strlen(entry)] = ' ';
232 memcpy(entry + (len - lencnt), no, lencnt);
234 addnstr (entry, len);
242 /* returns folder name of currently
243 * selected folder for <sidebar-open>
245 const char* sidebar_get_current (void) {
246 if (list_empty(Incoming))
248 return ((char*) ((BUFFY*) Incoming->data[CurBuffy])->path);
251 /* internally sets item to buf */
252 void sidebar_set_current (const char* buf) {
253 int i = buffy_lookup (buf);
260 /* fix counters for a context
261 * FIXME since ctx must not be of our business, move it elsewhere
263 void sidebar_set_buffystats (CONTEXT* Context) {
266 if (!Context || list_empty(Incoming) || (i = buffy_lookup (Context->path)) < 0)
268 tmp = (BUFFY*) Incoming->data[i];
269 tmp->new = Context->new;
270 tmp->msg_unread = Context->unread;
271 tmp->msgcount = Context->msgcount;
272 tmp->msg_flagged = Context->flagged;
275 void sidebar_draw_frames (void) {
278 if (!option(OPTMBOXPANE) || SidebarWidth==0)
281 delim_len=m_strlen(NONULL(SidebarDelim));
283 /* draw vertical delimiter */
284 SETCOLOR (MT_COLOR_SIDEBAR);
285 for (i = 0; i < LINES-1; i++) {
286 move (i, SidebarWidth - delim_len);
287 if (option (OPTASCIICHARS))
288 addstr (NONULL (SidebarDelim));
289 else if (!option (OPTASCIICHARS) && !m_strcmp(SidebarDelim, "|"))
291 else if ((Charset_is_utf8) && !m_strcmp(SidebarDelim, "|"))
292 addstr ("\342\224\202");
294 addstr (NONULL (SidebarDelim));
297 /* fill "gaps" at top+bottom */
298 SETCOLOR(MT_COLOR_STATUS);
299 for (i=0; i<SidebarWidth; i++) {
301 * if we don't have $status_on_top and have $help, fill top
302 * gap with spaces to get bg color
304 if (option(OPTSTATUSONTOP) || option(OPTHELP)) {
309 * if we don't have $status_on_top or we have $help, fill bottom
310 * gap with spaces to get bg color
312 if (!option(OPTSTATUSONTOP) || option(OPTHELP)) {
317 SETCOLOR (MT_COLOR_NORMAL);
320 /* actually draws something
321 * FIXME this needs some clue when to do it
323 int sidebar_draw (int menu) {
324 int first_line = option (OPTSTATUSONTOP) ? 1 : option (OPTHELP) ? 1 : 0,
325 last_line = LINES - 2 + (option (OPTSTATUSONTOP) && !option (OPTHELP) ? 1 : 0),
328 size_t delim_len = m_strlen(SidebarDelim);
329 char blank[SHORT_STRING];
331 known_lines=last_line-first_line;
333 /* initialize first time */
335 prev_show_value = option (OPTMBOXPANE);
339 if (TopBuffy==0 || CurBuffy==0)
342 /* save or restore the value SidebarWidth */
343 if (prev_show_value != option (OPTMBOXPANE)) {
344 if (!prev_show_value && option (OPTMBOXPANE)) {
345 /* after toggle: force recounting of all mail */
348 prev_show_value = option (OPTMBOXPANE);
351 if (SidebarWidth > 0 && option (OPTMBOXPANE)
352 && m_strlen(SidebarDelim) >= SidebarWidth) {
353 mutt_error (_("Value for sidebar_delim is too long. Disabling sidebar."));
355 unset_option (OPTMBOXPANE);
359 if (SidebarWidth == 0 || !option (OPTMBOXPANE))
362 sidebar_draw_frames();
364 if (list_empty(Incoming))
367 /* actually print items */
368 for (i = TopBuffy, line=first_line; i < Incoming->length && line < last_line; i++) {
369 tmp = (BUFFY*) Incoming->data[i];
372 SETCOLOR (MT_COLOR_INDICATOR);
373 else if (tmp->new > 0)
374 SETCOLOR (MT_COLOR_NEW);
375 else if (tmp->msg_flagged > 0)
376 SETCOLOR (MT_COLOR_FLAGGED);
378 SETCOLOR (MT_COLOR_NORMAL);
381 line += make_sidebar_entry (tmp->path, i, SidebarWidth-delim_len);
384 SETCOLOR (MT_COLOR_NORMAL);
386 /* fill with blanks to bottom */
387 memset(&blank, ' ', sizeof(blank));
388 for (; line < last_line; line++) {
390 addnstr (blank, SidebarWidth-delim_len);
395 /* returns index of new item with new mail or -1 */
396 static int exist_next_new () {
398 if (list_empty(Incoming))
401 while (i < Incoming->length)
402 if (((BUFFY*) Incoming->data[i++])->new > 0)
407 /* returns index of prev item with new mail or -1 */
408 static int exist_prev_new () {
410 if (list_empty(Incoming))
414 if (((BUFFY*) Incoming->data[i--])->new > 0)
419 void sidebar_scroll (int op, int menu) {
422 if (!SidebarWidth || list_empty(Incoming))
426 case OP_SIDEBAR_NEXT:
427 if (!option (OPTSIDEBARNEWMAILONLY)) {
428 if (CurBuffy + 1 == Incoming->length) {
429 mutt_error (_("You are on the last mailbox."));
434 } /* the fall-through is intentional */
435 case OP_SIDEBAR_NEXT_NEW:
436 if ((i = exist_next_new ()) < 0) {
437 mutt_error (_("No next mailboxes with new mail."));
443 case OP_SIDEBAR_PREV:
444 if (!option (OPTSIDEBARNEWMAILONLY)) {
446 mutt_error (_("You are on the first mailbox."));
451 } /* the fall-through is intentional */
452 case OP_SIDEBAR_PREV_NEW:
453 if ((i = exist_prev_new ()) < 0) {
454 mutt_error (_("No previous mailbox with new mail."));
461 case OP_SIDEBAR_SCROLL_UP:
463 mutt_error (_("You are on the first mailbox."));
466 CurBuffy -= known_lines;
470 case OP_SIDEBAR_SCROLL_DOWN:
471 if (CurBuffy + 1 == Incoming->length) {
472 mutt_error (_("You are on the last mailbox."));
475 CurBuffy += known_lines;
476 if (CurBuffy >= Incoming->length)
477 CurBuffy = Incoming->length - 1;