Andreas Krennmair:
[apps/madmutt.git] / sidebar.c
1 /*
2  * Copyright (C) ????-2004 Justin Hibbits <jrh29@po.cwru.edu>
3  * Copyright (C) 2004 Thomer M. Gil <mutt@thomer.com>
4  * 
5  *     This program is free software; you can redistribute it and/or modify
6  *     it under the terms of the GNU General Public License as published by
7  *     the Free Software Foundation; either version 2 of the License, or
8  *     (at your option) any later version.
9  * 
10  *     This program is distributed in the hope that it will be useful,
11  *     but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *     GNU General Public License for more details.
14  * 
15  *     You should have received a copy of the GNU General Public License
16  *     along with this program; if not, write to the Free Software
17  *     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
18  */
19
20
21
22 #include "mutt.h"
23 #include "mutt_menu.h"
24 #include "mutt_curses.h"
25 #include "sidebar.h"
26 #include "buffy.h"
27 #include <libgen.h>
28 #include "keymap.h"
29 #include <ctype.h>
30
31 /*BUFFY *CurBuffy = 0;*/
32 static BUFFY *TopBuffy = 0;
33 static BUFFY *BottomBuffy = 0;
34 static int known_lines = 0;
35 static short initialized = 0;
36 static int prev_show_value;
37 static short saveSidebarWidth;
38 static char *entry = 0;
39
40 static int quick_log10 (int n)
41 {
42   int len = 0;
43
44   for (; n > 9; len++, n /= 10);
45   return (++len);
46 }
47
48 /* CurBuffy should contain a valid buffy 
49  * mailbox before calling this function!!! */
50 void calc_boundaries (int menu)
51 {
52   BUFFY *tmp = Incoming;
53   int position;
54   int i, count, mailbox_position;
55
56   /* correct known_lines if it has changed because of a window resize */
57   if (known_lines != LINES) {
58     known_lines = LINES;
59   }
60   /* fix all the prev links on all the mailboxes
61    * FIXME move this over to buffy.c where it belongs */
62   for (; tmp->next != 0; tmp = tmp->next)
63     tmp->next->prev = tmp;
64
65   /* calculate the position of the current mailbox */
66   position = 1;
67   tmp = Incoming;
68   while (tmp != CurBuffy) {
69     position++;
70     tmp = tmp->next;
71   }
72   /* calculate the size of the screen we can use */
73   count = LINES - 2 - (menu != MENU_PAGER || option (OPTSTATUSONTOP));
74   /* calculate the position of the current mailbox on the screen */
75   mailbox_position = position % count;
76   if (mailbox_position == 0)
77     mailbox_position = count;
78   /* determine topbuffy */
79   TopBuffy = CurBuffy;
80   for (i = mailbox_position; i > 1; i--)
81     TopBuffy = TopBuffy->prev;
82   /* determine bottombuffy */
83   BottomBuffy = CurBuffy;
84   for (i = mailbox_position; i < count && BottomBuffy->next; i++)
85     BottomBuffy = BottomBuffy->next;
86 }
87
88 static char *shortened_hierarchy (char *box)
89 {
90   int dots = 0;
91   char *last_dot;
92   int i, j;
93   char *new_box;
94
95   for (i = 0; i < strlen (box); ++i) {
96     if (box[i] == '.')
97       ++dots;
98     else if (isupper (box[i]))
99       return (safe_strdup (box));
100   }
101   last_dot = strrchr (box, '.');
102   if (last_dot) {
103     ++last_dot;
104     new_box = safe_malloc (strlen (last_dot) + 2 * dots + 1);
105     new_box[0] = box[0];
106     for (i = 1, j = 1; i < strlen (box); ++i) {
107       if (box[i] == '.') {
108         new_box[j++] = '.';
109         new_box[j] = 0;
110         if (&box[i + 1] != last_dot) {
111           new_box[j++] = box[i + 1];
112           new_box[j] = 0;
113         }
114         else {
115           strcat (&new_box[j], last_dot);
116           break;
117         }
118       }
119     }
120     return new_box;
121   }
122   return safe_strdup (box);
123 }
124
125 char *make_sidebar_entry (char *box, int size, int new, int flagged)
126 {
127   int i = 0, dlen, max, shortened = 0;
128   int offset;
129
130   if (SidebarWidth > COLS)
131     SidebarWidth = COLS;
132
133   dlen = mutt_strlen (SidebarDelim);
134   max = SidebarWidth - dlen - 1;
135
136   safe_realloc (&entry, SidebarWidth + 1);
137   entry[SidebarWidth] = 0;
138   for (; i < SidebarWidth; entry[i++] = ' ');
139 #if USE_IMAP
140   if (ImapHomeNamespace && strlen (ImapHomeNamespace) > 0) {
141     if (strncmp (box, ImapHomeNamespace, strlen (ImapHomeNamespace)) == 0
142         && strcmp (box, ImapHomeNamespace) != 0) {
143       box += strlen (ImapHomeNamespace) + 1;
144     }
145   }
146 #endif
147   max -= quick_log10 (size);
148   if (new)
149     max -= quick_log10 (new) + 2;
150   if (flagged > 0)
151     max -= quick_log10 (flagged) + 2;
152   if (option (OPTSHORTENHIERARCHY) && mutt_strlen (box) > max) {
153     box = shortened_hierarchy (box);
154     shortened = 1;
155   }
156   i = strlen (box);
157   strncpy (entry, box, i < SidebarWidth - dlen ? i : SidebarWidth - dlen);
158
159   if (new) {
160     if (flagged > 0) {
161       offset =
162         SidebarWidth - 5 - quick_log10 (size) - dlen - quick_log10 (new) -
163         quick_log10 (flagged);
164       if (offset < 0)
165         offset = 0;
166       snprintf (entry + offset, SidebarWidth - dlen - offset + 1,
167                 "% d(%d)[%d]", size, new, flagged);
168     }
169     else {
170       offset =
171         SidebarWidth - 3 - quick_log10 (size) - dlen - quick_log10 (new);
172       if (offset < 0)
173         offset = 0;
174       snprintf (entry + offset, SidebarWidth - dlen - offset + 1,
175                 "% d(%d)", size, new);
176     }
177   }
178   else {
179     if (flagged > 0) {
180       offset =
181         SidebarWidth - 3 - quick_log10 (size) - dlen - quick_log10 (flagged);
182       if (offset < 0)
183         offset = 0;
184       snprintf (entry + offset, SidebarWidth - dlen - offset + 1,
185                 "% d[%d]", size, flagged);
186     }
187     else {
188       offset = SidebarWidth - 1 - quick_log10 (size) - dlen;
189       if (offset < 0)
190         offset = 0;
191       snprintf (entry + offset, SidebarWidth - dlen - offset + 1,
192                 "% d", size);
193     }
194   }
195
196   if (option (OPTSHORTENHIERARCHY) && shortened) {
197     free (box);
198   }
199   return entry;
200 }
201
202 void set_curbuffy (char buf[LONG_STRING])
203 {
204   BUFFY *tmp = CurBuffy = Incoming;
205
206   if (!Incoming)
207     return;
208
209   while (1) {
210     if (!strcmp (tmp->path, buf)) {
211       CurBuffy = tmp;
212       break;
213     }
214
215     if (tmp->next)
216       tmp = tmp->next;
217     else
218       break;
219   }
220 }
221
222 void set_buffystats (CONTEXT * Context)
223 {
224   BUFFY *tmp = Incoming;
225
226   if (!Context)
227     return;
228   while (tmp) {
229     if (strcmp (tmp->path, Context->path) == 0) {
230       tmp->new = Context->new;
231       tmp->msg_unread = Context->unread;
232       tmp->msgcount = Context->msgcount;
233       tmp->msg_flagged = Context->flagged;
234       break;
235     }
236     tmp = tmp->next;
237   }
238 }
239
240 int draw_sidebar (int menu)
241 {
242
243   int lines = option (OPTHELP) ? 1 : 0;
244   BUFFY *tmp;
245   short delim_len = mutt_strlen (SidebarDelim);
246
247   /* initialize first time */
248   if (!initialized) {
249     prev_show_value = option (OPTMBOXPANE);
250     saveSidebarWidth = SidebarWidth;
251     if (!option (OPTMBOXPANE))
252       SidebarWidth = 0;
253     initialized = 1;
254   }
255
256   /* save or restore the value SidebarWidth */
257   if (prev_show_value != option (OPTMBOXPANE)) {
258     if (prev_show_value && !option (OPTMBOXPANE)) {
259       saveSidebarWidth = SidebarWidth;
260       SidebarWidth = 0;
261     }
262     else if (!prev_show_value && option (OPTMBOXPANE)) {
263       SidebarWidth = saveSidebarWidth;
264       /* after toggle: force recounting of all mail */
265       mutt_buffy_check (2);
266     }
267     prev_show_value = option (OPTMBOXPANE);
268   }
269
270   if (SidebarWidth > 0 && option (OPTMBOXPANE)
271       && mutt_strlen (SidebarDelim) >= SidebarWidth) {
272     mutt_error (_("Value for sidebar_delim is too long. Disabling sidebar."));
273     sleep (2);
274     unset_option (OPTMBOXPANE);
275     return (0);
276   }
277
278   if (SidebarWidth == 0 || !option (OPTMBOXPANE))
279     return 0;
280
281   /* draw the divider */
282   /* SETCOLOR(MT_COLOR_STATUS); */
283   SETCOLOR (MT_COLOR_SIDEBAR);
284   for (lines = 1;
285        lines < LINES - 1 - (menu != MENU_PAGER || option (OPTSTATUSONTOP));
286        lines++) {
287     move (lines, SidebarWidth - delim_len);
288     if (option (OPTASCIICHARS))
289       addstr (NONULL (SidebarDelim));
290     else if (!option (OPTASCIICHARS) && !strcmp (SidebarDelim, "|"))
291       addch (ACS_VLINE);
292     else if ((Charset_is_utf8) && !strcmp (SidebarDelim, "|"))
293       addstr ("\342\224\202");
294     else
295       addstr (NONULL (SidebarDelim));
296   }
297   SETCOLOR (MT_COLOR_NORMAL);
298
299   if (Incoming == 0)
300     return 0;
301   lines = option (OPTHELP) ? 1 : 0;     /* go back to the top */
302
303   if (CurBuffy == 0)
304     CurBuffy = Incoming;
305 #if 0
306   if (known_lines != LINES || TopBuffy == 0 || BottomBuffy == 0)
307 #endif
308     calc_boundaries (menu);
309
310   tmp = TopBuffy;
311
312   for (;
313        tmp && lines < LINES - 1 - (menu != MENU_PAGER
314                                    || option (OPTSTATUSONTOP));
315        tmp = tmp->next) {
316     if (tmp == CurBuffy)
317       SETCOLOR (MT_COLOR_INDICATOR);
318     else if (tmp->msg_flagged > 0)
319       SETCOLOR (MT_COLOR_FLAGGED);
320     else if (tmp->msg_unread > 0)
321       SETCOLOR (MT_COLOR_NEW);
322     else
323       SETCOLOR (MT_COLOR_NORMAL);
324
325     move (lines, 0);
326     if (option (OPTSIDEBARNEWMAILONLY)) {
327       if (tmp->msg_unread > 0) {
328         if (Context && !strcmp (tmp->path, Context->path)) {
329           printw ("%.*s", SidebarWidth - delim_len,
330                   make_sidebar_entry (basename (tmp->path),
331                                       Context->msgcount, Context->unread,
332                                       Context->flagged));
333           tmp->msg_unread = Context->unread;
334           tmp->msgcount = Context->msgcount;
335           tmp->msg_flagged = Context->flagged;
336         }
337         else
338           printw ("%.*s", SidebarWidth - delim_len,
339                   make_sidebar_entry (basename (tmp->path),
340                                       tmp->msgcount, tmp->msg_unread,
341                                       tmp->msg_flagged));
342         lines++;
343       }
344     }
345     else {
346       if (Context && !strcmp (tmp->path, Context->path)) {
347         printw ("%.*s", SidebarWidth - delim_len,
348                 make_sidebar_entry (basename (tmp->path),
349                                     Context->msgcount, Context->unread,
350                                     Context->flagged));
351         tmp->msg_unread = Context->unread;
352         tmp->msgcount = Context->msgcount;
353         tmp->msg_flagged = Context->flagged;
354       }
355       else
356         printw ("%.*s", SidebarWidth - delim_len,
357                 make_sidebar_entry (basename (tmp->path),
358                                     tmp->msgcount, tmp->msg_unread,
359                                     tmp->msg_flagged));
360       lines++;
361     }
362   }
363   SETCOLOR (MT_COLOR_NORMAL);
364   for (; lines < LINES - 1 - (menu != MENU_PAGER || option (OPTSTATUSONTOP));
365        lines++) {
366     int i = 0;
367
368     move (lines, 0);
369     for (; i < SidebarWidth - delim_len; i++)
370       addch (' ');
371   }
372   return 0;
373 }
374
375 BUFFY *exist_next_new ()
376 {
377   BUFFY *tmp = CurBuffy;
378
379   if (tmp == NULL)
380     return NULL;
381   while (tmp->next != NULL) {
382     tmp = tmp->next;
383     if (tmp->msg_unread)
384       return tmp;
385   }
386   return NULL;
387 }
388
389 BUFFY *exist_prev_new ()
390 {
391   BUFFY *tmp = CurBuffy;
392
393   if (tmp == NULL)
394     return NULL;
395   while (tmp->prev != NULL) {
396     tmp = tmp->prev;
397     if (tmp->msg_unread)
398       return tmp;
399   }
400   return NULL;
401 }
402
403
404 void scroll_sidebar (int op, int menu)
405 {
406   BUFFY *tmp;
407
408   if (!SidebarWidth)
409     return;
410   if (!CurBuffy)
411     return;
412
413   switch (op) {
414   case OP_SIDEBAR_NEXT:
415     if (!option (OPTSIDEBARNEWMAILONLY)) {
416       if (CurBuffy->next == NULL) {
417         mutt_error (_("You are on the last mailbox."));
418         return;
419       }
420       CurBuffy = CurBuffy->next;
421       break;
422     }                           /* the fall-through is intentional */
423   case OP_SIDEBAR_NEXT_NEW:
424     if ((tmp = exist_next_new ()) == NULL) {
425       mutt_error (_("No next mailboxes with new mail."));
426       return;
427     }
428     else
429       CurBuffy = tmp;
430     break;
431   case OP_SIDEBAR_PREV:
432     if (!option (OPTSIDEBARNEWMAILONLY)) {
433       if (CurBuffy->prev == NULL) {
434         mutt_error (_("You are on the first mailbox."));
435         return;
436       }
437       CurBuffy = CurBuffy->prev;
438       break;
439     }                           /* the fall-through is intentional */
440   case OP_SIDEBAR_PREV_NEW:
441     if ((tmp = exist_prev_new ()) == NULL) {
442       mutt_error (_("No previous mailbox with new mail."));
443       return;
444     }
445     else
446       CurBuffy = tmp;
447     break;
448
449   case OP_SIDEBAR_SCROLL_UP:
450     CurBuffy = TopBuffy;
451     if (CurBuffy != Incoming) {
452       calc_boundaries (menu);
453       CurBuffy = CurBuffy->prev;
454     }
455     break;
456   case OP_SIDEBAR_SCROLL_DOWN:
457     CurBuffy = BottomBuffy;
458     if (CurBuffy->next) {
459       calc_boundaries (menu);
460       CurBuffy = CurBuffy->next;
461     }
462     break;
463   default:
464     return;
465   }
466   calc_boundaries (menu);
467   draw_sidebar (menu);
468 }