summaryrefslogtreecommitdiff
path: root/frm
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2005-03-03 11:42:20 +0000
committerSergey Poznyakoff <gray@gnu.org.ua>2005-03-03 11:42:20 +0000
commit891f9c44ccf15caccba072d9525f08c374772c62 (patch)
tree4c340f19f8863c9b116bac1792dae27243d77fe3 /frm
parent14746c8197a81e1d464f2a385f3b08de4c214912 (diff)
downloadmailutils-891f9c44ccf15caccba072d9525f08c374772c62.tar.gz
mailutils-891f9c44ccf15caccba072d9525f08c374772c62.tar.bz2
Added to the repository
Diffstat (limited to 'frm')
-rw-r--r--frm/common.c599
-rw-r--r--frm/from.c157
2 files changed, 756 insertions, 0 deletions
diff --git a/frm/common.c b/frm/common.c
new file mode 100644
index 000000000..bc6ad1a3a
--- /dev/null
+++ b/frm/common.c
@@ -0,0 +1,599 @@
1/* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 1999, 2000, 2001, 2002, 2003,
3 2004, 2005 Free Software Foundation, Inc.
4
5 GNU Mailutils 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, or (at your option)
8 any later version.
9
10 GNU Mailutils 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 GNU Mailutils; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
18
19#include <frm.h>
20
21char *show_field; /* Show this header field instead of the default
22 `From: Subject:' pair. -f option */
23int show_to; /* Additionally display To: field. -l option */
24int show_number; /* Prefix each line with the message number. -n */
25int frm_debug;
26
27
28
29/* Get the number of columns on the screen
30 First try an ioctl() call, not all shells set the COLUMNS environ.
31 If ioctl does not succeed on stdout, try it on /dev/tty, as we
32 may work via a pipe.
33
34 This function was taken from mail/util.c. It should probably reside
35 in the library */
36int
37util_getcols (void)
38{
39 struct winsize ws;
40
41 ws.ws_col = ws.ws_row = 0;
42 if (ioctl (1, TIOCGWINSZ, (char *) &ws) < 0)
43 {
44 int fd = open ("/dev/tty", O_RDWR);
45 ioctl (fd, TIOCGWINSZ, (char *) &ws);
46 close (fd);
47 }
48 if (ws.ws_row == 0)
49 {
50 const char *columns = getenv ("COLUMNS");
51 if (columns)
52 ws.ws_col = strtol (columns, NULL, 10);
53 }
54 return ws.ws_col;
55}
56
57
58/* Charset magic */
59static char *output_charset = NULL;
60
61const char *
62get_charset ()
63{
64 char *tmp;
65
66 if (!output_charset)
67 {
68 char locale[32];
69
70 memset (locale, 0, sizeof (locale));
71
72 /* Try to deduce the charset from LC_ALL or LANG variables */
73
74 tmp = getenv ("LC_ALL");
75 if (!tmp)
76 tmp = getenv ("LANG");
77
78 if (tmp)
79 {
80 char *sp = NULL;
81 char *lang;
82 char *terr;
83
84 strncpy (locale, tmp, sizeof (locale) - 1);
85
86 lang = strtok_r (locale, "_", &sp);
87 terr = strtok_r (NULL, ".", &sp);
88 output_charset = strtok_r (NULL, "@", &sp);
89
90 if (output_charset)
91 output_charset = xstrdup (output_charset);
92 else
93 output_charset = mu_charset_lookup (lang, terr);
94
95 if (!output_charset)
96 output_charset = "ASCII";
97 }
98 }
99 return output_charset;
100}
101
102
103/* BIDI support (will be moved to lib when it's ready) */
104#ifdef HAVE_LIBFRIBIDI
105
106static int fb_charset_num = -1;
107FriBidiChar *logical;
108char *outstring;
109size_t logical_size;
110
111void
112alloc_logical (size_t size)
113{
114 logical = xmalloc (size * sizeof (logical[0]));
115 logical_size = size;
116 outstring = xmalloc (size);
117}
118
119void
120puts_bidi (char *string)
121{
122 if (fb_charset_num == -1)
123 {
124 fb_charset_num = fribidi_parse_charset (get_charset ());
125 if (fb_charset_num && frm_debug)
126 mu_error (_("fribidi failed to recognize charset `%s'"),
127 get_charset ());
128 }
129
130 if (fb_charset_num == 0)
131 puts (string);
132 else
133 {
134 FriBidiStrIndex len;
135 FriBidiCharType base = FRIBIDI_TYPE_ON;
136 fribidi_boolean log2vis;
137
138 static FriBidiChar *visual;
139 static size_t visual_size;
140
141
142 len = fribidi_charset_to_unicode (fb_charset_num,
143 string, strlen (string),
144 logical);
145
146 if (len + 1 > visual_size)
147 {
148 visual_size = len + 1;
149 visual = xrealloc (visual, visual_size * sizeof *visual);
150 }
151
152 /* Create a bidi string. */
153 log2vis = fribidi_log2vis (logical, len, &base,
154 /* output */
155 visual, NULL, NULL, NULL);
156
157 if (log2vis)
158 {
159 FriBidiStrIndex idx, st;
160 FriBidiStrIndex new_len;
161
162 for (idx = 0; idx < len;)
163 {
164 FriBidiStrIndex wid, inlen;
165
166 wid = 3 * logical_size;
167 st = idx;
168
169 if (fb_charset_num != FRIBIDI_CHARSET_CAP_RTL)
170 {
171 while (wid > 0 && idx < len)
172 wid -= fribidi_wcwidth (visual[idx++]);
173 }
174 else
175 {
176 while (wid > 0 && idx < len)
177 {
178 wid--;
179 idx++;
180 }
181 }
182
183 if (wid < 0 && idx > st + 1)
184 idx--;
185 inlen = idx - st;
186
187 new_len = fribidi_unicode_to_charset (fb_charset_num,
188 visual + st, inlen,
189 outstring);
190 printf ("%s", outstring);
191 }
192 putchar ('\n');
193 }
194 else
195 {
196 /* Print the string as is */
197 puts (string);
198 }
199 }
200}
201#else
202# define alloc_logical(s)
203# define puts_bidi puts
204#endif
205
206
207/* Output functions */
208
209/* Number of columns in output:
210
211 Maximum 4 message number, to, from, subject -ln
212 Default 2 from, subject [none]
213 Minimum 1 FIELD -f FIELD
214*/
215
216static int numfields; /* Number of output fields */
217static int fieldwidth[4]; /* Field start positions */
218static char *linebuf; /* Output line buffer */
219static size_t linemax; /* Size of linebuf */
220static size_t linepos; /* Position in the output line buffer */
221static int curfield; /* Current output field */
222static int nextstart; /* Start position of the next field */
223static int curcol; /* Current output column */
224
225typedef void (*fmt_formatter) (const char *fmt, ...);
226
227static fmt_formatter format_field;
228
229void
230print_line ()
231{
232 if (linebuf)
233 {
234 puts_bidi (linebuf);
235 linebuf[0] = 0;
236 linepos = 0;
237 curcol = nextstart = 0;
238 }
239 else
240 putchar ('\n');
241 curfield = 0;
242}
243
244void
245format_field_simple (const char *fmt, ...)
246{
247 va_list ap;
248 if (curfield++)
249 putchar ('\t');
250 va_start (ap, fmt);
251 vprintf (fmt, ap);
252 va_end (ap);
253}
254
255void
256format_field_align (const char *fmt, ...)
257{
258 size_t n, width;
259 va_list ap;
260
261 va_start (ap, fmt);
262 if (nextstart != 0)
263 {
264 if (curcol >= nextstart)
265 {
266 if (curfield == numfields - 1)
267 {
268 puts_bidi (linebuf);
269 linepos = 0;
270 printf ("%*s", nextstart, "");
271 }
272 else
273 {
274 linebuf[linepos++] = ' ';
275 curcol++;
276 }
277 }
278 else if (nextstart != curcol)
279 {
280 /* align to field start */
281 n = snprintf (linebuf + linepos, linemax - linepos,
282 "%*s", nextstart - curcol, "");
283 linepos += n;
284 curcol = nextstart;
285 }
286 }
287
288 n = vsnprintf (linebuf + linepos, linemax - linepos, fmt, ap);
289 va_end (ap);
290
291 /* Compute output width */
292 if (curfield == numfields - 1)
293 {
294 for ( ; n > 0; n--)
295 {
296 int c = linebuf[linepos + n];
297 linebuf[linepos + n] = 0;
298 width = mbswidth (linebuf + linepos, 0);
299 if (width <= fieldwidth[curfield])
300 break;
301 linebuf[linepos + n] = c;
302 }
303 }
304 else
305 width = mbswidth (linebuf + linepos, 0);
306
307 /* Increment counters */
308 linepos += n;
309 curcol += width;
310 nextstart += fieldwidth[curfield++];
311}
312
313void
314init_output (size_t s)
315{
316 int i;
317 size_t width = 0;
318
319 if (s == 0)
320 {
321 format_field = format_field_simple;
322 return;
323 }
324
325 format_field = format_field_align;
326
327 /* Allocate the line buffer */
328 linemax = s * MB_LEN_MAX + 1;
329 linebuf = xmalloc (linemax);
330 alloc_logical (s);
331
332 /* Set up column widths */
333 if (show_number)
334 fieldwidth[numfields++] = 5;
335
336 if (show_to)
337 fieldwidth[numfields++] = 20;
338
339 if (show_field)
340 fieldwidth[numfields++] = 0;
341 else
342 {
343 fieldwidth[numfields++] = 20;
344 fieldwidth[numfields++] = 0;
345 }
346
347 for (i = 0; i < numfields; i++)
348 width += fieldwidth[i];
349
350 fieldwidth[numfields-1] = util_getcols () - width;
351}
352
353
354/*
355 FIXME: Generalize this function and move it
356 to `mailbox/locale.c'. Do the same with the one
357 from `from/from.c' and `mail/util.c'...
358*/
359static char *
360rfc2047_decode_wrapper (char *buf, size_t buflen)
361{
362 int rc;
363 char *tmp;
364 const char *charset = get_charset ();
365
366 if (strcmp (charset, "ASCII") == 0)
367 return strdup (buf);
368
369 rc = rfc2047_decode (charset, buf, &tmp);
370 if (rc)
371 {
372 if (frm_debug)
373 mu_error (_("Cannot decode line `%s': %s"),
374 buf, mu_strerror (rc));
375 return strdup (buf);
376 }
377
378 return tmp;
379}
380
381/* Retrieve the Personal Name from the header To: or From: */
382static int
383get_personal (header_t hdr, const char *field, char **personal)
384{
385 char *hfield;
386 int status;
387
388 status = header_aget_value_unfold (hdr, field, &hfield);
389 if (status == 0)
390 {
391 address_t address = NULL;
392 char *s;
393
394 address_create (&address, hfield);
395
396 address_aget_personal (address, 1, &s);
397 address_destroy (&address);
398 if (s == NULL)
399 s = hfield;
400 else
401 free (hfield);
402
403 *personal = rfc2047_decode_wrapper (s, strlen (s));
404 free (s);
405 }
406 return status;
407}
408
409/* Observer action used to perform mailbox scanning. See the comment
410 to frm_scan below.
411
412 FIXME: The observer action paradygm does not allow for making
413 procedure-data closure, as it should. So, for the time being
414 the following static variables are used instead: */
415
416static frm_select_t select_message; /* Message selection function */
417static size_t msg_index; /* Index (1-based) of the current
418 message */
419
420/* Observable action is being called on discovery of each message. */
421/* FIXME: The format of the display is poorly done, please correct. */
422static int
423action (observer_t o, size_t type)
424{
425 int status;
426
427 switch (type)
428 {
429 case MU_EVT_MESSAGE_ADD:
430 {
431 mailbox_t mbox = observer_get_owner (o);
432 message_t msg = NULL;
433 header_t hdr = NULL;
434 attribute_t attr = NULL;
435
436 msg_index++;
437
438 mailbox_get_message (mbox, msg_index, &msg);
439 message_get_attribute (msg, &attr);
440 message_get_header (msg, &hdr);
441
442 if (!select_message (msg_index, msg))
443 break;
444
445 if (show_number)
446 format_field ("%4lu:", (u_long) msg_index);
447
448 if (show_to)
449 {
450 char *hto;
451 status = get_personal (hdr, MU_HEADER_TO, &hto);
452
453 if (status == 0)
454 {
455 format_field ("(%s)", hto);
456 free (hto);
457 }
458 else
459 format_field ("(none)");
460 }
461
462 if (show_field) /* FIXME: This should be also rfc2047_decode. */
463 {
464 char *hfield;
465 status = header_aget_value_unfold (hdr, show_field, &hfield);
466 if (status == 0)
467 {
468 format_field ("%s", hfield);
469 free (hfield);
470 }
471 else
472 format_field ("");
473 }
474 else
475 {
476 char *tmp;
477 status = get_personal (hdr, MU_HEADER_FROM, &tmp);
478 if (status == 0)
479 {
480 format_field ("%s", tmp);
481 free (tmp);
482 }
483 else
484 format_field ("");
485
486 status = header_aget_value_unfold (hdr, MU_HEADER_SUBJECT,
487 &tmp);
488 if (status == 0)
489 {
490 char *s = rfc2047_decode_wrapper (tmp, strlen (tmp));
491 format_field ("%s", s);
492 free (s);
493 free (tmp);
494 }
495 }
496 print_line ();
497 break;
498 }
499
500 case MU_EVT_MAILBOX_PROGRESS:
501 /* Noop. */
502 break;
503 }
504 return 0;
505}
506
507static void
508frm_abort (mailbox_t *mbox)
509{
510 int status;
511
512 if ((status = mailbox_close (*mbox)) != 0)
513 {
514 url_t url;
515
516 mu_error (_("Could not close <%s>: %s."),
517 url_to_string (url), mu_strerror (status));
518 exit (3);
519 }
520
521 mailbox_destroy (mbox);
522 exit (3);
523}
524
525/* Scan the mailbox MAILBOX_NAME using FUN as the selection function.
526 FUN takes as its argument message number and the message itself
527 (message_t). It returns non-zero if that message is to be displayed
528 and zero otherwise.
529
530 Upon finishing scanning, the function places the overall number of
531 the messages processed into the memory location pointed to by
532 TOTAL */
533void
534frm_scan (char *mailbox_name, frm_select_t fun, size_t *total)
535{
536 mailbox_t mbox;
537 int status;
538 url_t url;
539
540 status = mailbox_create_default (&mbox, mailbox_name);
541 if (status != 0)
542 {
543 mu_error (_("Could not create mailbox <%s>: %s."),
544 mailbox_name ? mailbox_name : _("default"),
545 mu_strerror (status));
546 exit (3);
547 }
548
549 if (frm_debug)
550 {
551 mu_debug_t debug;
552 mailbox_get_debug (mbox, &debug);
553 mu_debug_set_level (debug, MU_DEBUG_TRACE|MU_DEBUG_PROT);
554 }
555
556 mailbox_get_url (mbox, &url);
557
558 status = mailbox_open (mbox, MU_STREAM_READ);
559 if (status == ENOENT)
560 *total = 0;
561 else if (status != 0)
562 {
563 mu_error (_("Could not open mailbox <%s>: %s."),
564 url_to_string (url), mu_strerror (status));
565 frm_abort (&mbox);
566 }
567 else
568 {
569 observer_t observer;
570 observable_t observable;
571
572 select_message = fun;
573 msg_index = 0;
574
575 observer_create (&observer, mbox);
576 observer_set_action (observer, action, mbox);
577 mailbox_get_observable (mbox, &observable);
578 observable_attach (observable, MU_EVT_MESSAGE_ADD, observer);
579
580 status = mailbox_scan (mbox, 1, total);
581 if (status != 0)
582 {
583 mu_error (_("Could not scan mailbox <%s>: %s."),
584 url_to_string (url), mu_strerror (status));
585 frm_abort (&mbox);
586 }
587
588 observable_detach (observable, observer);
589 observer_destroy (&observer, mbox);
590
591 if ((status = mailbox_close (mbox)) != 0)
592 {
593 mu_error (_("Could not close <%s>: %s."),
594 url_to_string (url), mu_strerror (status));
595 exit (3);
596 }
597 }
598 mailbox_destroy (&mbox);
599}
diff --git a/frm/from.c b/frm/from.c
new file mode 100644
index 000000000..e8a09553b
--- /dev/null
+++ b/frm/from.c
@@ -0,0 +1,157 @@
1/* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2005 Free Software Foundation, Inc.
3
4 GNU Mailutils is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
8
9 GNU Mailutils is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with GNU Mailutils; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
17
18#include <frm.h>
19
20int count_only;
21char *sender_option;
22char *mailbox_name;
23
24const char *program_version = "from (" PACKAGE_STRING ")";
25static char doc[] = N_("GNU from -- display from and subject");
26
27static struct argp_option options[] = {
28 {"count", 'c', NULL, 0, N_("Just print a count of messages and exit.")},
29 {"sender", 's', N_("ADDRESS"), 0,
30 N_("Print only mail from addresses containing the supplied string") },
31 {"file", 'f', N_("FILE"), 0,
32 N_("Read mail from FILE") },
33 {"debug", 'd', NULL, 0, N_("Enable debugging output"), 0},
34 {0, 0, 0, 0}
35};
36
37static error_t
38parse_opt (int key, char *arg, struct argp_state *state)
39{
40 switch (key)
41 {
42 case 'c':
43 count_only = 1;
44 break;
45
46 case 's':
47 sender_option = arg;
48 break;
49
50 case 'f':
51 mailbox_name = arg;
52 break;
53
54 case 'd':
55 frm_debug++;
56 break;
57
58 default:
59 return ARGP_ERR_UNKNOWN;
60 }
61 return 0;
62}
63
64static struct argp argp = {
65 options,
66 parse_opt,
67 N_("[OPTIONS] [USER]"),
68 doc,
69};
70
71static const char *capa[] = {
72 "common",
73 "license",
74 "mailbox",
75#ifdef WITH_TLS
76 "tls",
77#endif
78 NULL
79};
80
81static int
82from_select (size_t index, message_t msg)
83{
84 if (count_only)
85 return 0;
86
87 if (sender_option)
88 {
89 int rc = 0;
90 header_t hdr = NULL;
91 char *sender;
92 message_get_header (msg, &hdr);
93
94 if (header_aget_value_unfold (hdr, MU_HEADER_FROM, &sender) == 0)
95 {
96 if (strstr (sender, sender_option))
97 rc = 1;
98 free (sender);
99 }
100
101 return rc;
102 }
103
104 return 1;
105}
106
107int
108main (int argc, char **argv)
109{
110 int c;
111 int status = 0;
112 size_t total;
113
114 /* Native Language Support */
115 mu_init_nls ();
116
117 /* register the formats. */
118 mu_register_all_mbox_formats ();
119
120 mu_argp_init (program_version, NULL);
121#ifdef WITH_TLS
122 mu_tls_init_client_argp ();
123#endif
124 mu_argp_parse (&argp, &argc, &argv, 0, capa, &c, NULL);
125
126 if (argc - c > 1)
127 {
128 mu_error (_("Too many arguments"));
129 exit (1);
130 }
131 else if (argc - c > 0)
132 {
133 if (mailbox_name)
134 {
135 mu_error (_("Both --from option and user name are specified"));
136 exit (1);
137 }
138
139 mailbox_name = xmalloc (strlen (argv[c]) + 2);
140 mailbox_name[0] = '%';
141 strcpy (mailbox_name + 1, argv[c]);
142 }
143
144 init_output (0);
145
146 frm_scan (mailbox_name, from_select, &total);
147
148 if (count_only)
149 {
150 printf (ngettext ("There is %lu message in your incoming mailbox.\n",
151 "There are %lu messages in your incoming mailbox.\n",
152 total),
153 (unsigned long) total);
154 }
155 return 0;
156}
157

Return to:

Send suggestions and report system problems to the System administrator.