~ubuntu-branches/debian/squeeze/alpine/squeeze

« back to all changes in this revision

Viewing changes to pith/keyword.c

  • Committer: Bazaar Package Importer
  • Author(s): Asheesh Laroia
  • Date: 2007-02-17 13:17:42 UTC
  • Revision ID: james.westby@ubuntu.com-20070217131742-99x5c6cpg1pbkdhw
Tags: upstream-0.82+dfsg
ImportĀ upstreamĀ versionĀ 0.82+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#if !defined(lint) && !defined(DOS)
 
2
static char rcsid[] = "$Id: keyword.c 203 2006-10-26 17:23:46Z hubert@u.washington.edu $";
 
3
#endif
 
4
 
 
5
/*
 
6
 * ========================================================================
 
7
 * Copyright 2006 University of Washington
 
8
 *
 
9
 * Licensed under the Apache License, Version 2.0 (the "License");
 
10
 * you may not use this file except in compliance with the License.
 
11
 * You may obtain a copy of the License at
 
12
 *
 
13
 *     http://www.apache.org/licenses/LICENSE-2.0
 
14
 *
 
15
 * ========================================================================
 
16
 */
 
17
 
 
18
#include "../pith/headers.h"
 
19
#include "../pith/keyword.h"
 
20
#include "../pith/state.h"
 
21
#include "../pith/flag.h"
 
22
#include "../pith/string.h"
 
23
#include "../pith/status.h"
 
24
#include "../pith/util.h"
 
25
 
 
26
 
 
27
/*
 
28
 * Internal prototypes
 
29
 */
 
30
 
 
31
 
 
32
/*
 
33
 * Read the keywords array into a KEYWORD_S structure.
 
34
 * Make sure that all of the strings are UTF-8.
 
35
 */
 
36
KEYWORD_S *
 
37
init_keyword_list(char **keywordarray)
 
38
{
 
39
    char     **t, *nickname, *keyword;
 
40
    KEYWORD_S *head = NULL, *new, *kl = NULL;
 
41
 
 
42
    for(t = keywordarray; t && *t && **t; t++){
 
43
        nickname = keyword = NULL;
 
44
        get_pair(*t, &nickname, &keyword, 0, 0);
 
45
        new = new_keyword_s(keyword, nickname);
 
46
        if(keyword)
 
47
          fs_give((void **) &keyword);
 
48
 
 
49
        if(nickname)
 
50
          fs_give((void **) &nickname);
 
51
 
 
52
        if(kl)
 
53
          kl->next = new;
 
54
 
 
55
        kl = new;
 
56
 
 
57
        if(!head)
 
58
          head = kl;
 
59
    }
 
60
 
 
61
    return(head);
 
62
}
 
63
 
 
64
 
 
65
KEYWORD_S *
 
66
new_keyword_s(char *keyword, char *nickname)
 
67
{
 
68
    KEYWORD_S *kw = NULL;
 
69
 
 
70
    kw = (KEYWORD_S *) fs_get(sizeof(*kw));
 
71
    memset(kw, 0, sizeof(*kw));
 
72
 
 
73
    if(keyword && *keyword)
 
74
      kw->kw = cpystr(keyword);
 
75
 
 
76
    if(nickname && *nickname)
 
77
      kw->nick = cpystr(nickname);
 
78
    
 
79
    return(kw);
 
80
}
 
81
 
 
82
 
 
83
void
 
84
free_keyword_list(KEYWORD_S **kl)
 
85
{
 
86
    if(kl && *kl){
 
87
        if((*kl)->next)
 
88
          free_keyword_list(&(*kl)->next);
 
89
 
 
90
        if((*kl)->kw)
 
91
          fs_give((void **) &(*kl)->kw);
 
92
 
 
93
        if((*kl)->nick)
 
94
          fs_give((void **) &(*kl)->nick);
 
95
 
 
96
        fs_give((void **) kl);
 
97
    }
 
98
}
 
99
 
 
100
 
 
101
/*
 
102
 * Return a pointer to the keyword associated with a nickname, or the
 
103
 * input itself if no match.
 
104
 */
 
105
char *
 
106
nick_to_keyword(char *nick)
 
107
{
 
108
    KEYWORD_S *kw;
 
109
    char      *ret;
 
110
 
 
111
    ret = nick;
 
112
    for(kw = ps_global->keywords; kw; kw = kw->next)
 
113
      if(!strcmp(nick, kw->nick ? kw->nick : kw->kw ? kw->kw : "")){
 
114
          if(kw->nick)
 
115
            ret = kw->kw;
 
116
 
 
117
          break;
 
118
      }
 
119
    
 
120
    return(ret);
 
121
}
 
122
 
 
123
 
 
124
/*
 
125
 * Return a pointer to the nickname associated with a keyword, or the
 
126
 * input itself if no match.
 
127
 */
 
128
char *
 
129
keyword_to_nick(char *keyword)
 
130
{
 
131
    KEYWORD_S *kw;
 
132
    char      *ret;
 
133
 
 
134
    ret = keyword;
 
135
    for(kw = ps_global->keywords; kw; kw = kw->next)
 
136
      if(!strcmp(keyword, kw->kw ? kw->kw : "")){
 
137
          if(kw->nick)
 
138
            ret = kw->nick;
 
139
 
 
140
          break;
 
141
      }
 
142
    
 
143
    return(ret);
 
144
}
 
145
 
 
146
 
 
147
int
 
148
user_flag_is_set(MAILSTREAM *stream, long unsigned int rawno, char *keyword)
 
149
{
 
150
    int           j, is_set = 0;
 
151
    MESSAGECACHE *mc;
 
152
 
 
153
    if(stream){
 
154
        if(rawno > 0L && stream
 
155
           && rawno <= stream->nmsgs
 
156
           && (mc = mail_elt(stream, rawno)) != NULL){
 
157
            j = user_flag_index(stream, keyword);
 
158
            if(j >= 0 && j < NUSERFLAGS && ((1 << j) & mc->user_flags))
 
159
              is_set++;
 
160
        }
 
161
    }
 
162
        
 
163
    return(is_set);
 
164
}
 
165
 
 
166
 
 
167
/*
 
168
 * Returns the bit position of the keyword in stream, else -1.
 
169
 */
 
170
int
 
171
user_flag_index(MAILSTREAM *stream, char *keyword)
 
172
{
 
173
    int i, retval = -1;
 
174
 
 
175
    if(stream && keyword){
 
176
        for(i = 0; i < NUSERFLAGS; i++)
 
177
          if(stream->user_flags[i] && !strucmp(keyword, stream->user_flags[i])){
 
178
              retval = i;
 
179
              break;
 
180
          }
 
181
    }
 
182
 
 
183
    return(retval);
 
184
}
 
185
 
 
186
 
 
187
/*----------------------------------------------------------------------
 
188
  Build flags string based on requested flags and what's set in messagecache
 
189
 
 
190
   Args: mc -- message cache element to dig the flags out of
 
191
         flags -- flags to test
 
192
         flagbuf -- place to write string representation of bits
 
193
 
 
194
 Result: flags represented in bits and mask written in flagbuf
 
195
 ----*/
 
196
void
 
197
flag_string(MESSAGECACHE *mc, long int flags, char *flagbuf, size_t flagbuflen)
 
198
{
 
199
    char *p;
 
200
 
 
201
    if(flagbuflen > 0)
 
202
      *(p = flagbuf) = '\0';
 
203
 
 
204
    if(!mc)
 
205
      return;
 
206
 
 
207
    if((flags & F_DEL) && mc->deleted)
 
208
      sstrncpy(&p, "\\DELETED ", flagbuflen-(p-flagbuf));
 
209
 
 
210
    if((flags & F_ANS) && mc->answered)
 
211
      sstrncpy(&p, "\\ANSWERED ", flagbuflen-(p-flagbuf));
 
212
 
 
213
    if((flags & F_FLAG) && mc->flagged)
 
214
      sstrncpy(&p, "\\FLAGGED ", flagbuflen-(p-flagbuf));
 
215
 
 
216
    if((flags & F_SEEN) && mc->seen)
 
217
      sstrncpy(&p, "\\SEEN ", flagbuflen-(p-flagbuf));
 
218
 
 
219
    if(p != flagbuf && (flagbuflen-(p-flagbuf)>0))
 
220
      *--p = '\0';
 
221
}
 
222
 
 
223
 
 
224
/*
 
225
 * Find the last message in dstn_stream's folder that has message_id
 
226
 * equal to the argument. Set its keywords equal to the keywords which
 
227
 * are set in message mc from stream kw_stream.
 
228
 *
 
229
 * If you just saved the message you're looking for, it is a good idea
 
230
 * to send a ping over before you call this routine.
 
231
 *
 
232
 * Args:  kw_stream -- stream containing message mc
 
233
 *            mcsrc -- mail_elt for the source message
 
234
 *      dstn_stream -- where the new message is
 
235
 *       message_id -- the message id of the new message
 
236
 *            guess -- this is a positive integer, for example, 10. If it
 
237
 *                       is set we will first try to find the message_id
 
238
 *                       within the last "guess" messages in the folder,
 
239
 *                       unless the whole folder isn't much bigger than that
 
240
 */
 
241
void
 
242
set_keywords_in_msgid_msg(MAILSTREAM *kw_stream, MESSAGECACHE *mcsrc,
 
243
                          MAILSTREAM *dstn_stream, char *message_id, long int guess)
 
244
{
 
245
    SEARCHPGM *pgm = NULL;
 
246
    long        newmsgno;
 
247
    int         iter = 0, k;
 
248
    MESSAGECACHE *mc;
 
249
    extern MAILSTREAM *mm_search_stream;
 
250
    extern long        mm_search_count;
 
251
 
 
252
    if(!(kw_stream && dstn_stream))
 
253
      return;
 
254
 
 
255
    mm_search_count = 0L;
 
256
    mm_search_stream = dstn_stream;
 
257
    while(mm_search_count == 0L && iter++ < 2
 
258
          && (pgm = mail_newsearchpgm()) != NULL){
 
259
        pgm->message_id = mail_newstringlist();
 
260
        pgm->message_id->text.data = (unsigned char *) cpystr(message_id);
 
261
        pgm->message_id->text.size = strlen(message_id);
 
262
 
 
263
        if(iter == 1){
 
264
            /* lots of messages? restrict to last guess message on first try */
 
265
            if(dstn_stream->nmsgs > guess + 40L){
 
266
                pgm->msgno = mail_newsearchset();
 
267
                pgm->msgno->first = dstn_stream->nmsgs - guess;
 
268
                pgm->msgno->first = MIN(MAX(pgm->msgno->first, 1),
 
269
                                        dstn_stream->nmsgs);
 
270
                pgm->msgno->last  = dstn_stream->nmsgs;
 
271
            }
 
272
            else
 
273
              iter++;
 
274
        }
 
275
 
 
276
        pine_mail_search_full(dstn_stream, NULL, pgm, SE_NOPREFETCH | SE_FREE);
 
277
        if(mm_search_count){
 
278
            for(newmsgno=dstn_stream->nmsgs; newmsgno > 0L; newmsgno--)
 
279
              if((mc = mail_elt(dstn_stream, newmsgno)) && mc->searched)
 
280
                break;
 
281
                  
 
282
            if(newmsgno > 0L)
 
283
              for(k = 0; k < NUSERFLAGS; k++)
 
284
                if(mcsrc && mcsrc->user_flags & (1 << k)
 
285
                   && kw_stream->user_flags[k]
 
286
                   && kw_stream->user_flags[k][0]){
 
287
                    int i;
 
288
 
 
289
                    /*
 
290
                     * Check to see if we know it is impossible to set
 
291
                     * this keyword before we try.
 
292
                     */
 
293
                    if(dstn_stream->kwd_create ||
 
294
                       (((i = user_flag_index(dstn_stream,
 
295
                                              kw_stream->user_flags[k])) >= 0)
 
296
                        && i < NUSERFLAGS)){
 
297
                      mail_flag(dstn_stream, long2string(newmsgno),
 
298
                                kw_stream->user_flags[k], ST_SET);
 
299
                    }
 
300
                    else{
 
301
                      int some_defined = 0, w;
 
302
                      static time_t last_status_message = 0;
 
303
                      time_t now;
 
304
                      char b[200], c[200], *p;
 
305
 
 
306
                      for(i = 0; !some_defined && i < NUSERFLAGS; i++)
 
307
                        if(dstn_stream->user_flags[i])
 
308
                          some_defined++;
 
309
                    
 
310
                      /*
 
311
                       * Some unusual status message handling here. We'd
 
312
                       * like to print out one status message for every
 
313
                       * keyword missed, but if that happens every time
 
314
                       * you save to a particular folder, that would get
 
315
                       * annoying. So we only print out the first for each
 
316
                       * save or aggregate save.
 
317
                       */
 
318
                      if((now=time((time_t *) 0)) - last_status_message > 3){
 
319
                        last_status_message = now;
 
320
                        if(some_defined){
 
321
                          snprintf(b, sizeof(b), "Losing keyword \"%.30s\". No more keywords allowed in ", keyword_to_nick(kw_stream->user_flags[k]));
 
322
                          w = MIN((ps_global->ttyo ? ps_global->ttyo->screen_cols : 80) - strlen(b) - 1 - 2, sizeof(c)-1);
 
323
                          p = short_str(STREAMNAME(dstn_stream), c, sizeof(c), w,
 
324
                                        FrontDots);
 
325
                          q_status_message2(SM_ORDER, 3, 3, "%s%s!", b, p);
 
326
                        }
 
327
                        else{
 
328
                          snprintf(b, sizeof(b), "Losing keyword \"%.30s\". Can't add keywords in ", keyword_to_nick(kw_stream->user_flags[k]));
 
329
                          w = MIN((ps_global->ttyo ? ps_global->ttyo->screen_cols : 80) - strlen(b) - 1 - 2, sizeof(b)-1);
 
330
                          p = short_str(STREAMNAME(dstn_stream), c, sizeof(c), w,
 
331
                                        FrontDots);
 
332
                          q_status_message2(SM_ORDER, 3, 3, "%s%s!", b, p);
 
333
                        }
 
334
                      }
 
335
 
 
336
                      if(some_defined){
 
337
                        dprint((1, "Losing keyword \"%s\". No more keywords allowed in %s\n", kw_stream->user_flags[k], dstn_stream->mailbox ? dstn_stream->mailbox : "target folder"));
 
338
                      }
 
339
                      else{
 
340
                        dprint((1, "Losing keyword \"%s\". Can't add keywords in %s\n", kw_stream->user_flags[k], dstn_stream->mailbox ? dstn_stream->mailbox : "target folder"));
 
341
                      }
 
342
                    }
 
343
                }
 
344
        }
 
345
    }
 
346
}
 
347
 
 
348
 
 
349
long
 
350
get_msgno_by_msg_id(MAILSTREAM *stream, char *message_id, MSGNO_S *msgmap)
 
351
{
 
352
    SEARCHPGM  *pgm = NULL;
 
353
    long        hint = mn_m2raw(msgmap, mn_get_cur(msgmap));
 
354
    long        newmsgno = -1L;
 
355
    int         iter = 0, k;
 
356
    MESSAGECACHE *mc;
 
357
    extern MAILSTREAM *mm_search_stream;
 
358
    extern long        mm_search_count;
 
359
 
 
360
    if(!(message_id && message_id[0]))
 
361
      return(newmsgno);
 
362
 
 
363
    mm_search_count = 0L;
 
364
    mm_search_stream = stream;
 
365
    while(mm_search_count == 0L && iter++ < 3
 
366
          && (pgm = mail_newsearchpgm()) != NULL){
 
367
        pgm->message_id = mail_newstringlist();
 
368
        pgm->message_id->text.data = (unsigned char *) cpystr(message_id);
 
369
        pgm->message_id->text.size = strlen(message_id);
 
370
 
 
371
        if(iter > 1 || hint > stream->nmsgs)
 
372
          iter++;
 
373
 
 
374
        if(iter == 1){
 
375
            /* restrict to hint message on first try */
 
376
            pgm->msgno = mail_newsearchset();
 
377
            pgm->msgno->first = pgm->msgno->last = hint;
 
378
        }
 
379
        else if(iter == 2){
 
380
            /* restrict to last 50 messages on 2nd try */
 
381
            pgm->msgno = mail_newsearchset();
 
382
            if(stream->nmsgs > 100L)
 
383
              pgm->msgno->first = stream->nmsgs-50L;
 
384
            else{
 
385
                pgm->msgno->first = 1L;
 
386
                iter++;
 
387
            }
 
388
 
 
389
            pgm->msgno->last = stream->nmsgs;
 
390
        }
 
391
 
 
392
        pine_mail_search_full(stream, NULL, pgm, SE_NOPREFETCH | SE_FREE);
 
393
 
 
394
        if(mm_search_count){
 
395
            for(newmsgno=stream->nmsgs; newmsgno > 0L; newmsgno--)
 
396
              if((mc = mail_elt(stream, newmsgno)) && mc->searched)
 
397
                break;
 
398
        }
 
399
    }
 
400
 
 
401
    return(mn_raw2m(msgmap, newmsgno));
 
402
}
 
403
 
 
404
 
 
405
/*
 
406
 * These chars are not allowed in keywords.
 
407
 *
 
408
 * Returns 0 if ok, 1 if not.
 
409
 * Returns an allocated error message on error.
 
410
 */
 
411
int
 
412
keyword_check(char *kw, char **error)
 
413
{
 
414
    register char *t;
 
415
    char buf[100];
 
416
 
 
417
    if(!kw || !kw[0])
 
418
      return 1;
 
419
 
 
420
    kw = nick_to_keyword(kw);
 
421
 
 
422
    if((t = strindex(kw, SPACE)) ||
 
423
       (t = strindex(kw, '{'))   ||
 
424
       (t = strindex(kw, '('))   ||
 
425
       (t = strindex(kw, ')'))   ||
 
426
       (t = strindex(kw, ']'))   ||
 
427
       (t = strindex(kw, '%'))   ||
 
428
       (t = strindex(kw, '"'))   ||
 
429
       (t = strindex(kw, '\\'))  ||
 
430
       (t = strindex(kw, '*'))){
 
431
        char s[4];
 
432
        s[0] = '"';
 
433
        s[1] = *t;
 
434
        s[2] = '"';
 
435
        s[3] = '\0';
 
436
        if(error){
 
437
            snprintf(buf, sizeof(buf), "%s not allowed in keywords",
 
438
                *t == SPACE ?
 
439
                    "Spaces" :
 
440
                    *t == '"' ?
 
441
                        "Quotes" :
 
442
                        *t == '%' ?
 
443
                            "Percents" :
 
444
                            s);
 
445
            *error = cpystr(buf);
 
446
        }
 
447
 
 
448
        return 1;
 
449
    }
 
450
 
 
451
    return 0;
 
452
}