Rocco Rutte:
[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   for (; n > 9; len++, n /= 10)
44     ;
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   {
70     position++;
71     tmp = tmp->next;
72   }
73   /* calculate the size of the screen we can use */
74   count = LINES - 2 - (menu != MENU_PAGER || option (OPTSTATUSONTOP));
75   /* calculate the position of the current mailbox on the screen */
76   mailbox_position = position%count;
77   if (mailbox_position == 0) mailbox_position=count;
78   /* determine topbuffy */
79   TopBuffy = CurBuffy;
80   for(i = mailbox_position; i >1; i--) TopBuffy = TopBuffy->prev;
81   /* determine bottombuffy */
82   BottomBuffy = CurBuffy;
83   for(i = mailbox_position; i < count && BottomBuffy->next; i++)
84     BottomBuffy = BottomBuffy->next;
85 }
86
87 static char * shortened_hierarchy(char * box) {
88   int dots = 0;
89   char * last_dot;
90   int i,j;
91   char * new_box;
92   for (i=0;i<strlen(box);++i) {
93     if (box[i] == '.') ++dots;
94     else if (isupper (box[i])) 
95       return (safe_strdup (box));
96   }
97   last_dot = strrchr(box,'.');
98   if (last_dot) {
99     ++last_dot;
100     new_box = safe_malloc(strlen(last_dot)+2*dots+1);
101     new_box[0] = box[0];
102     for (i=1,j=1;i<strlen(box);++i) {
103       if (box[i] == '.') {
104         new_box[j++] = '.';
105         new_box[j] = 0;
106         if (&box[i+1] != last_dot) {
107           new_box[j++] = box[i+1];
108           new_box[j] = 0;
109         } else {
110           strcat(&new_box[j],last_dot);
111           break;
112         }
113       }
114     }
115     return new_box;
116   }
117   return safe_strdup(box);
118 }
119
120 char *make_sidebar_entry(char *box, int size, int new, int flagged)
121 {
122   int i = 0, dlen, max, shortened = 0;
123   int offset;
124
125   if (SidebarWidth > COLS)
126     SidebarWidth = COLS;
127
128   dlen = mutt_strlen(SidebarDelim);
129   max = SidebarWidth - dlen - 1;
130
131   safe_realloc(&entry, SidebarWidth + 1);
132   entry[SidebarWidth] = 0;
133   for (; i < SidebarWidth; entry[i++] = ' ' );
134 #if USE_IMAP
135   if (ImapHomeNamespace && strlen(ImapHomeNamespace)>0) {
136     if (strncmp(box,ImapHomeNamespace,strlen(ImapHomeNamespace))==0 && strcmp(box,ImapHomeNamespace)!=0) {
137       box+=strlen(ImapHomeNamespace)+1;
138     }
139   }
140 #endif
141   max -= quick_log10(size);
142   if (new)
143     max -= quick_log10(new) + 2;
144   if (flagged > 0)
145     max -= quick_log10(flagged) + 2;
146   if (option(OPTSHORTENHIERARCHY) && mutt_strlen(box) > max) {
147     box = shortened_hierarchy(box);
148     shortened = 1;
149   }
150   i = strlen(box);
151   strncpy( entry, box, i < SidebarWidth - dlen ? i :SidebarWidth - dlen);
152
153   if ( new ) {
154     if (flagged>0) {
155       offset = SidebarWidth - 5 - quick_log10(size) - dlen - quick_log10(new) - quick_log10(flagged);
156       if (offset<0) offset = 0;
157       snprintf(entry + offset, SidebarWidth - dlen - offset + 1,
158               "% d(%d)[%d]", size, new, flagged);
159     } else {
160       offset = SidebarWidth - 3 - quick_log10(size) - dlen - quick_log10(new);
161       if (offset<0) offset = 0;
162       snprintf(entry + offset, SidebarWidth - dlen - offset + 1,
163               "% d(%d)", size, new);
164     }
165   } else {
166     if (flagged>0) {
167       offset = SidebarWidth - 3 - quick_log10(size) - dlen - quick_log10(flagged);
168       if (offset<0) offset = 0;
169       snprintf( entry + offset, SidebarWidth - dlen - offset + 1,
170               "% d[%d]", size,flagged);
171     } else {
172       offset = SidebarWidth - 1 - quick_log10(size) - dlen;
173       if (offset<0) offset = 0;
174       snprintf( entry + offset, SidebarWidth - dlen - offset + 1,
175               "% d", size);
176     }
177   }
178
179   if (option(OPTSHORTENHIERARCHY) && shortened) {
180     free(box);
181   }
182   return entry;
183 }
184
185 void set_curbuffy(char buf[LONG_STRING])
186 {
187   BUFFY* tmp = CurBuffy = Incoming;
188
189   if (!Incoming)
190     return;
191
192   while(1) {
193     if(!strcmp(tmp->path, buf)) {
194       CurBuffy = tmp;
195       break;
196     }
197
198     if(tmp->next)
199       tmp = tmp->next;
200     else
201       break;
202   }
203 }
204
205 void set_buffystats (CONTEXT* Context)
206 {
207   BUFFY* tmp = Incoming;
208   if (!Context)
209     return;
210   while (tmp)
211   {
212     if (strcmp (tmp->path, Context->path) == 0)
213     {
214       tmp->new = Context->new;
215       tmp->msg_unread = Context->unread;
216       tmp->msgcount = Context->msgcount;
217       tmp->msg_flagged = Context->flagged;
218       break;
219     }
220     tmp = tmp->next;
221   }
222 }
223
224 int draw_sidebar(int menu) {
225
226   int lines = option(OPTHELP) ? 1 : 0;
227   BUFFY *tmp;
228   short delim_len = mutt_strlen (SidebarDelim);
229
230   /* initialize first time */
231   if(!initialized) {
232     prev_show_value = option(OPTMBOXPANE);
233     saveSidebarWidth = SidebarWidth;
234     if(!option(OPTMBOXPANE)) SidebarWidth = 0;
235     initialized = 1;
236   }
237
238   /* save or restore the value SidebarWidth */
239   if(prev_show_value != option(OPTMBOXPANE)) {
240     if(prev_show_value && !option(OPTMBOXPANE)) {
241       saveSidebarWidth = SidebarWidth;
242       SidebarWidth = 0;
243     } else if(!prev_show_value && option(OPTMBOXPANE)) {
244       SidebarWidth = saveSidebarWidth;
245       /* after toggle: force recounting of all mail */
246       mutt_buffy_check(2);
247     }
248     prev_show_value = option(OPTMBOXPANE);
249   }
250
251   if (SidebarWidth > 0 && option (OPTMBOXPANE) && mutt_strlen (SidebarDelim) >= SidebarWidth) {
252     mutt_error (_("Value for sidebar_delim is too long. Disabling sidebar."));
253     sleep (2);
254     unset_option (OPTMBOXPANE);
255     return (0);
256   }
257
258   if (SidebarWidth == 0 || !option (OPTMBOXPANE))
259     return 0;
260
261   /* draw the divider */
262   /* SETCOLOR(MT_COLOR_STATUS); */
263     SETCOLOR(MT_COLOR_SIDEBAR);
264   for (lines = 1;
265        lines < LINES-1-(menu != MENU_PAGER || option (OPTSTATUSONTOP)); lines++ ) {
266     move(lines, SidebarWidth - delim_len);
267     if (option (OPTASCIICHARS))
268       addstr (NONULL (SidebarDelim));
269     else if(!option(OPTASCIICHARS) && !strcmp(SidebarDelim,"|"))
270       addch(ACS_VLINE);
271     else if ((Charset_is_utf8) && !strcmp(SidebarDelim, "|"))
272       addstr ("\342\224\202");
273     else
274       addstr (NONULL (SidebarDelim));
275   }
276   SETCOLOR(MT_COLOR_NORMAL);
277
278   if ( Incoming == 0 ) return 0;
279   lines = option(OPTHELP) ? 1 : 0; /* go back to the top */
280
281   if ( CurBuffy == 0 ) CurBuffy = Incoming;
282 #if 0
283   if ( known_lines != LINES || TopBuffy == 0 || BottomBuffy == 0 ) 
284 #endif
285     calc_boundaries(menu);
286
287   tmp = TopBuffy;
288
289   for ( ; tmp && lines < LINES-1 - (menu != MENU_PAGER || option (OPTSTATUSONTOP)); tmp = tmp->next ) {
290     if ( tmp == CurBuffy )
291       SETCOLOR(MT_COLOR_INDICATOR);
292     else if ( tmp->msg_flagged > 0 )
293       SETCOLOR(MT_COLOR_FLAGGED);
294     else if ( tmp->msg_unread > 0 )
295       SETCOLOR(MT_COLOR_NEW);
296     else
297       SETCOLOR(MT_COLOR_NORMAL);
298
299     move( lines, 0 );
300     if (option(OPTSIDEBARNEWMAILONLY)) {
301       if (tmp->msg_unread > 0) {
302         if ( Context && !strcmp( tmp->path, Context->path ) ) {
303           printw( "%.*s", SidebarWidth - delim_len,
304                   make_sidebar_entry(basename(tmp->path),
305                                      Context->msgcount, Context->unread, Context->flagged));
306           tmp->msg_unread = Context->unread;
307           tmp->msgcount = Context->msgcount;
308           tmp->msg_flagged = Context->flagged;
309         }
310         else
311           printw( "%.*s", SidebarWidth - delim_len,
312                   make_sidebar_entry(basename(tmp->path),
313                                      tmp->msgcount,tmp->msg_unread, tmp->msg_flagged));
314         lines++;
315       }
316     } else {
317       if ( Context && !strcmp( tmp->path, Context->path ) ) {
318         printw( "%.*s", SidebarWidth - delim_len,
319                 make_sidebar_entry(basename(tmp->path),
320                                    Context->msgcount, Context->unread, Context->flagged));
321         tmp->msg_unread = Context->unread;
322         tmp->msgcount = Context->msgcount;
323         tmp->msg_flagged = Context->flagged;
324       }
325       else
326         printw( "%.*s", SidebarWidth - delim_len,
327                 make_sidebar_entry(basename(tmp->path),
328                                    tmp->msgcount,tmp->msg_unread, tmp->msg_flagged));
329       lines++;
330     }
331   }
332   SETCOLOR(MT_COLOR_NORMAL);
333   for ( ; lines < LINES - 1 - (menu != MENU_PAGER || option (OPTSTATUSONTOP)); lines++ ) {
334     int i = 0;
335     move( lines, 0 );
336     for ( ; i < SidebarWidth - delim_len; i++ )
337       addch(' ');
338   }
339   return 0;
340 }
341
342 BUFFY * exist_next_new()
343 {
344         BUFFY *tmp = CurBuffy;
345         if(tmp == NULL) return NULL;
346         while (tmp->next != NULL)
347         {
348                 tmp = tmp->next;
349                 if(tmp->msg_unread) return tmp;
350         }
351         return NULL;
352 }
353
354 BUFFY * exist_prev_new()
355 {
356         BUFFY *tmp = CurBuffy;
357         if(tmp == NULL) return NULL;
358         while (tmp->prev != NULL)
359         {
360                 tmp = tmp->prev;
361                 if(tmp->msg_unread) return tmp;
362         }
363         return NULL;
364 }     
365
366
367 void scroll_sidebar(int op, int menu)
368 {
369   BUFFY *tmp;
370
371   if(!SidebarWidth) return;
372   if(!CurBuffy) return;
373
374   switch (op) {
375     case OP_SIDEBAR_NEXT:
376       if (!option(OPTSIDEBARNEWMAILONLY)) {
377         if ( CurBuffy->next == NULL ) {
378           mutt_error (_("You are on the last mailbox."));
379           return;
380         }
381         CurBuffy = CurBuffy->next;
382         break;
383       } /* the fall-through is intentional */
384     case OP_SIDEBAR_NEXT_NEW:
385       if ( (tmp = exist_next_new()) == NULL) {
386         mutt_error (_("No next mailboxes with new mail."));
387         return;
388       }
389       else CurBuffy = tmp;
390       break;
391     case OP_SIDEBAR_PREV:
392       if (!option(OPTSIDEBARNEWMAILONLY)) {
393         if ( CurBuffy->prev == NULL ) {
394           mutt_error (_("You are on the first mailbox."));
395           return;
396         }
397         CurBuffy = CurBuffy->prev;
398        break;
399      } /* the fall-through is intentional */
400     case OP_SIDEBAR_PREV_NEW:
401       if ( (tmp = exist_prev_new()) == NULL) {
402         mutt_error (_("No previous mailbox with new mail."));
403         return;
404       }
405       else CurBuffy = tmp;
406       break;
407      
408     case OP_SIDEBAR_SCROLL_UP:
409       CurBuffy = TopBuffy;
410       if ( CurBuffy != Incoming ) {
411         calc_boundaries(menu);
412         CurBuffy = CurBuffy->prev;
413       }
414       break;
415     case OP_SIDEBAR_SCROLL_DOWN:
416       CurBuffy = BottomBuffy;
417       if ( CurBuffy->next ) {
418         calc_boundaries(menu);
419         CurBuffy = CurBuffy->next;
420       }
421       break;
422     default:
423       return;
424   }
425   calc_boundaries(menu);
426   draw_sidebar(menu);
427 }