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 <stdbool.h>
30 #include <ctype.h>
31
32 /*BUFFY *CurBuffy = 0;*/
33 static BUFFY *TopBuffy = 0;
34 static BUFFY *BottomBuffy = 0;
35 static int known_lines = 0;
36 static bool initialized = false;
37 static int prev_show_value;
38 static short saveSidebarWidth;
39 static char *entry = 0;
40
41 static int quick_log10(int n)
42 {
43   int len = 0;
44   for (; n > 9; len++, n /= 10)
45     ;
46   return (++len);
47 }
48
49 /* CurBuffy should contain a valid buffy 
50  * mailbox before calling this function!!! */
51 void calc_boundaries (int menu)
52 {
53   BUFFY *tmp = Incoming;
54   int position;
55   int i,count, mailbox_position;
56
57   /* correct known_lines if it has changed because of a window resize */
58   if ( known_lines != LINES ) {
59     known_lines = LINES;
60   }
61   /* fix all the prev links on all the mailboxes
62    * FIXME move this over to buffy.c where it belongs */
63   for ( ; tmp->next != 0; tmp = tmp->next )
64     tmp->next->prev = tmp;
65
66   /* calculate the position of the current mailbox */
67   position = 1;
68   tmp = Incoming;
69   while (tmp != CurBuffy)
70   {
71     position++;
72     tmp = tmp->next;
73   }
74   /* calculate the size of the screen we can use */
75   count = LINES - 2 - (menu != MENU_PAGER || option (OPTSTATUSONTOP));
76   /* calculate the position of the current mailbox on the screen */
77   mailbox_position = position%count;
78   if (mailbox_position == 0) mailbox_position=count;
79   /* determine topbuffy */
80   TopBuffy = CurBuffy;
81   for(i = mailbox_position; i >1; i--) 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   int dots = 0;
90   char * last_dot;
91   int i,j;
92   char * new_box;
93   for (i=0;i<strlen(box);++i) {
94     if (box[i] == '.') ++dots;
95     else if (isupper (box[i])) 
96       return (safe_strdup (box));
97   }
98   last_dot = strrchr(box,'.');
99   if (last_dot) {
100     ++last_dot;
101     new_box = safe_malloc(strlen(last_dot)+2*dots+1);
102     new_box[0] = box[0];
103     for (i=1,j=1;i<strlen(box);++i) {
104       if (box[i] == '.') {
105         new_box[j++] = '.';
106         new_box[j] = 0;
107         if (&box[i+1] != last_dot) {
108           new_box[j++] = box[i+1];
109           new_box[j] = 0;
110         } else {
111           strcat(&new_box[j],last_dot);
112           break;
113         }
114       }
115     }
116     return new_box;
117   }
118   return safe_strdup(box);
119 }
120
121 char *make_sidebar_entry(char *box, int size, int new, int flagged)
122 {
123   int i = 0, dlen, max, shortened = 0;
124   int offset;
125
126   if (SidebarWidth > COLS)
127     SidebarWidth = COLS;
128
129   dlen = mutt_strlen(SidebarDelim);
130   max = SidebarWidth - dlen - 1;
131
132   safe_realloc(&entry, SidebarWidth + 1);
133   entry[SidebarWidth] = 0;
134   for (; i < SidebarWidth; entry[i++] = ' ' );
135 #if USE_IMAP
136   if (ImapHomeNamespace && strlen(ImapHomeNamespace)>0) {
137     if (strncmp(box,ImapHomeNamespace,strlen(ImapHomeNamespace))==0 && strcmp(box,ImapHomeNamespace)!=0) {
138       box+=strlen(ImapHomeNamespace)+1;
139     }
140   }
141 #endif
142   max -= quick_log10(size);
143   if (new)
144     max -= quick_log10(new) + 2;
145   if (flagged > 0)
146     max -= quick_log10(flagged) + 2;
147   if (option(OPTSHORTENHIERARCHY) && mutt_strlen(box) > max) {
148     box = shortened_hierarchy(box);
149     shortened = 1;
150   }
151   i = strlen(box);
152   strncpy( entry, box, i < SidebarWidth - dlen ? i :SidebarWidth - dlen);
153
154   if ( new ) {
155     if (flagged>0) {
156       offset = SidebarWidth - 5 - quick_log10(size) - dlen - quick_log10(new) - quick_log10(flagged);
157       if (offset<0) offset = 0;
158       snprintf(entry + offset, SidebarWidth - dlen - offset + 1,
159               "% d(%d)[%d]", size, new, flagged);
160     } else {
161       offset = SidebarWidth - 3 - quick_log10(size) - dlen - quick_log10(new);
162       if (offset<0) offset = 0;
163       snprintf(entry + offset, SidebarWidth - dlen - offset + 1,
164               "% d(%d)", size, new);
165     }
166   } else {
167     if (flagged>0) {
168       offset = SidebarWidth - 3 - quick_log10(size) - dlen - quick_log10(flagged);
169       if (offset<0) offset = 0;
170       snprintf( entry + offset, SidebarWidth - dlen - offset + 1,
171               "% d[%d]", size,flagged);
172     } else {
173       offset = SidebarWidth - 1 - quick_log10(size) - dlen;
174       if (offset<0) offset = 0;
175       snprintf( entry + offset, SidebarWidth - dlen - offset + 1,
176               "% d", size);
177     }
178   }
179
180   if (option(OPTSHORTENHIERARCHY) && shortened) {
181     free(box);
182   }
183   return entry;
184 }
185
186 void set_curbuffy(char buf[LONG_STRING])
187 {
188   BUFFY* tmp = CurBuffy = Incoming;
189
190   if (!Incoming)
191     return;
192
193   while(1) {
194     if(!strcmp(tmp->path, buf)) {
195       CurBuffy = tmp;
196       break;
197     }
198
199     if(tmp->next)
200       tmp = tmp->next;
201     else
202       break;
203   }
204 }
205
206 void set_buffystats (CONTEXT* Context)
207 {
208   BUFFY* tmp = Incoming;
209   if (!Context)
210     return;
211   while (tmp)
212   {
213     if (strcmp (tmp->path, Context->path) == 0)
214     {
215       tmp->new = Context->new;
216       tmp->msg_unread = Context->unread;
217       tmp->msgcount = Context->msgcount;
218       tmp->msg_flagged = Context->flagged;
219       break;
220     }
221     tmp = tmp->next;
222   }
223 }
224
225 int draw_sidebar(int menu) {
226
227   int lines = option(OPTHELP) ? 1 : 0;
228   BUFFY *tmp;
229   short delim_len = mutt_strlen (SidebarDelim);
230
231   /* initialize first time */
232   if(!initialized) {
233     prev_show_value = option(OPTMBOXPANE);
234     saveSidebarWidth = SidebarWidth;
235     if(!option(OPTMBOXPANE)) SidebarWidth = 0;
236     initialized = true;
237   }
238
239   /* save or restore the value SidebarWidth */
240   if(prev_show_value != option(OPTMBOXPANE)) {
241     if(prev_show_value && !option(OPTMBOXPANE)) {
242       saveSidebarWidth = SidebarWidth;
243       SidebarWidth = 0;
244     } else if(!prev_show_value && option(OPTMBOXPANE)) {
245       SidebarWidth = saveSidebarWidth;
246       /* after toggle: force recounting of all mail */
247       mutt_buffy_check(2);
248     }
249     prev_show_value = option(OPTMBOXPANE);
250   }
251
252   if ( SidebarWidth == 0 ) return 0;
253
254   /* draw the divider */
255   /* SETCOLOR(MT_COLOR_STATUS); */
256     SETCOLOR(MT_COLOR_SIDEBAR);
257   for (lines = 1;
258        lines < LINES-1-(menu != MENU_PAGER || option (OPTSTATUSONTOP)); lines++ ) {
259     move(lines, SidebarWidth - delim_len);
260     addstr (NONULL (SidebarDelim));
261   }
262   SETCOLOR(MT_COLOR_NORMAL);
263
264   if ( Incoming == 0 ) return 0;
265   lines = option(OPTHELP) ? 1 : 0; /* go back to the top */
266
267   if ( CurBuffy == 0 ) CurBuffy = Incoming;
268 #if 0
269   if ( known_lines != LINES || TopBuffy == 0 || BottomBuffy == 0 ) 
270 #endif
271     calc_boundaries(menu);
272
273   tmp = TopBuffy;
274
275   for ( ; tmp && lines < LINES-1 - (menu != MENU_PAGER || option (OPTSTATUSONTOP)); tmp = tmp->next ) {
276     if ( tmp == CurBuffy )
277       SETCOLOR(MT_COLOR_INDICATOR);
278     else if ( tmp->msg_flagged > 0 )
279       SETCOLOR(MT_COLOR_FLAGGED);
280     else if ( tmp->msg_unread > 0 )
281       SETCOLOR(MT_COLOR_NEW);
282     else
283       SETCOLOR(MT_COLOR_NORMAL);
284
285     move( lines, 0 );
286     if ( Context && !strcmp( tmp->path, Context->path ) ) {
287       printw( "%.*s", SidebarWidth - delim_len,
288               make_sidebar_entry(basename(tmp->path),
289                                  Context->msgcount, Context->unread, Context->flagged));
290       tmp->msg_unread = Context->unread;
291       tmp->msgcount = Context->msgcount;
292       tmp->msg_flagged = Context->flagged;
293     }
294     else
295       printw( "%.*s", SidebarWidth - delim_len,
296               make_sidebar_entry(basename(tmp->path),
297                                  tmp->msgcount,tmp->msg_unread, tmp->msg_flagged));
298     lines++;
299   }
300   SETCOLOR(MT_COLOR_NORMAL);
301   for ( ; lines < LINES - 1 - (menu != MENU_PAGER || option (OPTSTATUSONTOP)); lines++ ) {
302     int i = 0;
303     move( lines, 0 );
304     for ( ; i < SidebarWidth - delim_len; i++ )
305       addch(' ');
306   }
307   return 0;
308 }
309
310 BUFFY * exist_next_new()
311 {
312         BUFFY *tmp = CurBuffy;
313         if(tmp == NULL) return NULL;
314         while (tmp->next != NULL)
315         {
316                 tmp = tmp->next;
317                 if(tmp->msg_unread) return tmp;
318         }
319         return NULL;
320 }
321
322 BUFFY * exist_prev_new()
323 {
324         BUFFY *tmp = CurBuffy;
325         if(tmp == NULL) return NULL;
326         while (tmp->prev != NULL)
327         {
328                 tmp = tmp->prev;
329                 if(tmp->msg_unread) return tmp;
330         }
331         return NULL;
332 }     
333
334
335 void scroll_sidebar(int op, int menu)
336 {
337   BUFFY *tmp;
338
339   if(!SidebarWidth) return;
340   if(!CurBuffy) return;
341
342   switch (op) {
343     case OP_SIDEBAR_NEXT:
344       if ( CurBuffy->next == NULL ) {
345         mutt_error (_("You are on the last mailbox."));
346         return;
347       }
348       CurBuffy = CurBuffy->next;
349       break;
350     case OP_SIDEBAR_NEXT_NEW:
351       if ( (tmp = exist_next_new()) == NULL) {
352         mutt_error (_("No next mailboxes with new mail."));
353         return;
354       }
355       else CurBuffy = tmp;
356       break;
357     case OP_SIDEBAR_PREV:
358       if ( CurBuffy->prev == NULL ) {
359         mutt_error (_("You are on the first mailbox."));
360         return;
361       }
362       CurBuffy = CurBuffy->prev;
363      break;
364     case OP_SIDEBAR_PREV_NEW:
365       if ( (tmp = exist_prev_new()) == NULL) {
366         mutt_error (_("No previous mailbox with new mail."));
367         return;
368       }
369       else CurBuffy = tmp;
370       break;
371      
372     case OP_SIDEBAR_SCROLL_UP:
373       CurBuffy = TopBuffy;
374       if ( CurBuffy != Incoming ) {
375         calc_boundaries(menu);
376         CurBuffy = CurBuffy->prev;
377       }
378       break;
379     case OP_SIDEBAR_SCROLL_DOWN:
380       CurBuffy = BottomBuffy;
381       if ( CurBuffy->next ) {
382         calc_boundaries(menu);
383         CurBuffy = CurBuffy->next;
384       }
385       break;
386     default:
387       return;
388   }
389   calc_boundaries(menu);
390   draw_sidebar(menu);
391 }