/*
elmo - ELectronic Mail Operator
Copyright (C) 2003, 2004 rzyjontko
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
----------------------------------------------------------------------
Different sring manipulation routines.
*/
/****************************************************************************
* IMPLEMENTATION HEADERS
****************************************************************************/
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include "eprintf.h"
#include "mail.h"
#include "xmalloc.h"
#include "wrapbox.h"
#include "misc.h"
#include "keymap.h"
#include "str.h"
#include "gettext.h"
#include "mime.h"
#include "rstring.h"
#include "property.h"
/****************************************************************************
* IMPLEMENTATION PRIVATE DEFINITIONS / ENUMERATIONS / SIMPLE TYPEDEFS
****************************************************************************/
#define FIRST_ALLOC 20
enum justify { JUSTIFY_LEFT = 0, JUSTIFY_RIGHT = 1};
/****************************************************************************
* IMPLEMENTATION PRIVATE CLASS PROTOTYPES / EXTERNAL CLASS REFERENCES
****************************************************************************/
/****************************************************************************
* IMPLEMENTATION PRIVATE STRUCTURES / UTILITY CLASSES
****************************************************************************/
/**
* This structure describes formatting sequence (i.e. %-020n)
* everything between % and the first letter is used to format
* a string.
* In the example above -020 means that we want the desired string
* be exactly 20 characters long, filled with spaces (leading 0),
* and justified to right (dash).
*
* To be more precise:
* len = 20
* character = 'n'
* fill = YES
* justify = JUSTIFY_RIGHT
*/
struct fmt_seq {
int fs_len;
int len;
char character;
struct {
enum yes_no fill : 1;
enum justify justify : 1;
} flags;
};
/****************************************************************************
* IMPLEMENTATION REQUIRED EXTERNAL REFERENCES (AVOID)
****************************************************************************/
/****************************************************************************
* IMPLEMENTATION PRIVATE DATA
****************************************************************************/
/****************************************************************************
* INTERFACE DATA
****************************************************************************/
/****************************************************************************
* IMPLEMENTATION PRIVATE FUNCTION PROTOTYPES
****************************************************************************/
/****************************************************************************
* IMPLEMENTATION PRIVATE FUNCTIONS
****************************************************************************/
static void
eval_fmt_seq (struct fmt_seq *fs, const char *s)
{
char *rest;
fs->fs_len = 0;
fs->len = 0;
fs->character = '\0';
fs->flags.fill = NO;
fs->flags.justify = JUSTIFY_LEFT;
if (*s != '%')
return;
s++;
if (*s == '-'){
fs->flags.justify = JUSTIFY_RIGHT;
s++;
fs->fs_len++;
}
if (*s == '0'){
fs->flags.fill = YES;
s++;
fs->fs_len++;
}
if (isdigit (*s)){
fs->len = strtol (s, &rest, 10);
if (rest)
fs->fs_len += rest - s;
s = rest;
}
fs->character = *s;
fs->fs_len++;
}
static void
put_string_fs (str_t *s, const char *t, struct fmt_seq *fs)
{
int spaces;
int t_len;
int w_len;
if (fs->len < 0)
fs->len = 0;
if (! t)
t = "";
t_len = strlen (t);
if (t_len <= fs->len){
w_len = t_len;
spaces = fs->len - t_len;
}
else if (fs->len != 0){
w_len = fs->len;
spaces = 0;
}
else {
w_len = t_len;
spaces = 0;
}
if (fs->flags.justify == JUSTIFY_LEFT){
str_put_string_len (s, t, w_len);
if (fs->flags.fill)
str_put_nchar (s, ' ', spaces);
}
else {
if (fs->flags.fill)
str_put_nchar (s, ' ', spaces);
str_put_string_len (s, t, w_len);
}
}
/**
* Suppose a mail:
* From: Johnny Masta Killa <johnny@masta.com>
* To: Bob The Ripper <bob@ripper.com>
* Subject: Bow before me!
* Date: Wed, 7 May 2003 15:36:46 +0200
*
*/
static int
put_mail_special (str_t *s, const char *fmt, mail_t *mail)
{
int size;
char *date;
struct fmt_seq fs;
eval_fmt_seq (&fs, fmt);
switch (fs.character){
case '%':
str_put_char (s, '%');
break;
/* Johnny Masta Killa */
case 'f':
put_string_fs (s, address_name (mail->from), &fs);
break;
/* Johnny Masta Killa <johnny@masta.com> */
case 'F':
if (mail->from)
put_string_fs (s, mail->from->full, &fs);
else
put_string_fs (s, NULL, &fs);
break;
/* Bob The Ripper */
case 't':
if (mail->to)
put_string_fs (s, address_name (mail->to->array[0]), &fs);
else
put_string_fs (s, NULL, &fs);
break;
/* Bob The Ripper <bob@ripper.com> */
case 'T':
if (mail->to && mail->to->count)
put_string_fs (s, mail->to->array[0]->full, &fs);
else
put_string_fs (s, NULL, &fs);
break;
/* Wed, 7 May 2003 15:36:46 +0200 */
case 'd':
put_string_fs (s, mail->date_str, &fs);
break;
/* 07 May */
case 'D':
date = date_string ("%b %d", mail->date);
put_string_fs (s, date, &fs);
xfree (date);
break;
/* Bow before me! */
case 's':
put_string_fs (s, mail->subject, &fs);
break;
/* JMK */
case 'i':
if (mail->from)
put_string_fs (s, mail->from->initials, &fs);
else
put_string_fs (s, NULL, &fs);
break;
/* (3.5K) */
case 'S':
size = wrapbox_mail_size (mail);
put_string_fs (s, human_size (size), &fs);
break;
/* these are flags */
case '$':
if (mail->flags & FLAG_FLAGGED)
str_put_char (s, 'F');
else if (mail->flags & FLAG_READ)
str_put_char (s, ' ');
else if (mail->flags & FLAG_OLD)
str_put_char (s, 'O');
else
str_put_char (s, 'N');
if (mail->flags & FLAG_TRASHED)
str_put_char (s, 'D');
else if (mail->flags & FLAG_FETCHED)
str_put_char (s, 'F');
else if (mail->flags & FLAG_ANSWERED)
str_put_char (s, 'r');
else if (mail->flags & FLAG_PASSED)
str_put_char (s, 'f');
else
str_put_char (s, ' ');
break;
/* attachments indicator */
case '?':
str_put_char (s,
mime_attachment_indicator (mail->mime));
break;
/* spam indicator */
case '#':
if (mail->flags & FLAG_SPAM)
str_put_char (s, '#');
else if (mail->flags & FLAG_LEGITIMATE
|| mail->flags & FLAG_NOSPAM)
str_put_char (s, ' ');
else
str_put_char (s, '?');
break;
}
return fs.fs_len;
}
static int
put_mail_special_desc (str_t *s, const char *fmt)
{
struct fmt_seq fs;
eval_fmt_seq (&fs, fmt);
switch (fs.character){
case '%':
str_put_char (s, '%');
break;
case 'f':
case 'F':
put_string_fs (s, _("From"), &fs);
break;
case 't':
case 'T':
put_string_fs (s, _("To"), &fs);
break;
case 'd':
case 'D':
put_string_fs (s, _("Date "), &fs);
break;
case 's':
put_string_fs (s, _("Subject"), &fs);
break;
case 'i':
put_string_fs (s, _("Initials"), &fs);
break;
case 'S':
put_string_fs (s, _("Size"), &fs);
break;
case '$':
str_put_string_len (s, " ", 2);
break;
case '?':
str_put_char (s, ' ');
break;
case '#':
str_put_char (s, ' ');
break;
}
return fs.fs_len;
}
static int
put_command_special (str_t *s, const char *fmt, const eprintf_command_t *cmd)
{
struct fmt_seq fs;
eval_fmt_seq (&fs, fmt);
switch (fs.character){
case '%':
str_put_char (s, '%');
break;
case 'p':
put_string_fs (s, cmd->command, & fs);
break;
case 'f':
put_string_fs (s, cmd->fname, & fs);
break;
case 'm':
put_string_fs (s, cmd->mime_type, & fs);
break;
case 'l':
str_sprintf (s, "%d", cmd->lineno);
break;
case 'c':
str_sprintf (s, "%d", cmd->col);
break;
case 'o':
str_sprintf (s, "%d", cmd->pos);
break;
}
return fs.fs_len;
}
static int
put_addr_special (str_t *s, const char *fmt, address_t *addr)
{
char *tmp;
struct fmt_seq fs;
eval_fmt_seq (&fs, fmt);
switch (fs.character){
case '%':
str_put_char (s, '%');
break;
case 'n':
put_string_fs (s, addr->name, &fs);
break;
case 'e':
put_string_fs (s, addr->email, &fs);
break;
case 'o':
if (addr->flags.bits.official)
str_put_char (s, 'o');
else
str_put_char (s, ' ');
break;
case 'f':
if (addr->flags.bits.foreign)
str_put_char (s, 'f');
else
str_put_char (s, ' ');
break;
case 's':
if (addr->flags.bits.sex == SEX_MALE)
str_put_char (s, 'M');
else if (addr->flags.bits.sex == SEX_FEMALE)
str_put_char (s, 'F');
else
str_put_char (s, '?');
break;
case 'g':
if (addr->groups == NULL)
put_string_fs (s, NULL, & fs);
else {
tmp = rstring_flatten (addr->groups, ", ");
put_string_fs (s, tmp, & fs);
xfree (tmp);
}
break;
}
return fs.fs_len;
}
static int
put_addr_desc_special (str_t *s, const char *fmt)
{
struct fmt_seq fs;
eval_fmt_seq (& fs, fmt);
switch (fs.character){
case '%':
str_put_char (s, '%');
break;
case 'n':
put_string_fs (s, _("Name"), & fs);
break;
case 'e':
put_string_fs (s, _("Email"), & fs);
break;
case 'o':
str_put_char (s, ' ');
break;
case 'f':
str_put_char (s, ' ');
break;
case 's':
str_put_char (s, ' ');
break;
case 'g':
put_string_fs (s, _("Groups"), & fs);
break;
}
return fs.fs_len;
}
static int
put_key_special (str_t *s, const char *fmt, struct key *key, int meta)
{
struct fmt_seq fs;
eval_fmt_seq (&fs, fmt);
switch (fs.character){
case '%':
str_put_char (s, '%');
break;
case 'k':
if (key == NULL)
put_string_fs (s, NULL, & fs);
else
put_string_fs (s,
key2string (key->key, meta),
&fs);
break;
case 'f':
if (key == NULL || key->exec == NULL)
put_string_fs (s, NULL, & fs);
else
put_string_fs (s, key->exec->name, &fs);
break;
case 'd':
if (key == NULL || key->exec == NULL)
put_string_fs (s, NULL, & fs);
else
put_string_fs (s, key->exec->desc, &fs);
break;
}
return fs.fs_len;
}
static int
put_box_special (str_t *s, const char *fmt, const char *box)
{
int unread;
char buf[16];
struct fmt_seq fs;
eval_fmt_seq (& fs, fmt);
switch (fs.character){
case '%':
str_put_char (s, '%');
break;
case 'n':
put_string_fs (s, box, & fs);
break;
case 't':
sprintf (buf, "%d",
wrapbox_box_mail_count (box, NULL));
put_string_fs (s, buf, & fs);
break;
case 'u':
wrapbox_box_mail_count (box, & unread);
sprintf (buf, "%d", unread);
put_string_fs (s, buf, & fs);
break;
}
return fs.fs_len;
}
static int
put_mime_special (str_t *s, const char *fmt, mime_t *mime)
{
char *fname;
char *enc;
char *type;
struct fmt_seq fs;
eval_fmt_seq (& fs, fmt);
switch (fs.character){
case '%':
str_put_char (s, '%');
break;
case 'f':
if (mime->file_name == NULL)
fname = "<mail content>";
else {
fname = strrchr (mime->file_name, '/');
if (fname)
fname++;
else
fname = mime->file_name;
}
put_string_fs (s, fname, & fs);
break;
case 't':
type = (mime->type) ? mime->type : "text/plain";
put_string_fs (s, type, & fs);
break;
case 's':
put_string_fs (s, human_size (mime->off_end
- mime->off_start),
& fs);
break;
case 'c':
if (mime->charset)
put_string_fs (s, mime->charset, & fs);
break;
case 'C':
if (mime->charset){
str_put_char (s, ',');
str_put_char (s, ' ');
fs.len -= 2;
put_string_fs (s, mime->charset, & fs);
}
break;
case 'e':
put_string_fs (s, mime_encoding_str (mime), & fs);
break;
case 'E':
enc = mime_encoding_str (mime);
if (enc && *enc){
str_put_char (s, ',');
str_put_char (s, ' ');
fs.len -= 2;
put_string_fs (s, enc, & fs);
}
break;
}
return fs.fs_len;
}
static int
put_rstring_special (str_t *s, const char *fmt, rstring_t *values)
{
int num;
char *txt;
struct fmt_seq fs;
eval_fmt_seq (& fs, fmt);
if (islower (fs.character)){
num = fs.character - 'a';
if (num < values->count){
txt = property_get (values->array[num]);
put_string_fs (s, txt, & fs);
xfree (txt);
}
}
else {
switch (fs.character){
case '%':
str_put_char (s, '%');
break;
}
}
return fs.fs_len;
}
static void
substitute_mail (const char *fmt, mail_t *mail, str_t *str)
{
int fs_len;
const char *seek;
for (seek = fmt; *seek; seek++){
if (*seek == '%'){
fs_len = put_mail_special (str, seek, mail);
seek += fs_len;
}
else
str_put_char (str, *seek);
}
}
static void
substitute_mail_desc (const char *fmt, str_t *str)
{
int fs_len;
const char *seek;
for (seek = fmt; *seek; seek++){
if (*seek == '%'){
fs_len = put_mail_special_desc (str, seek);
seek += fs_len;
}
else
str_put_char (str, *seek);
}
str_put_string (str, _("Subject"));
}
static char *
substitute_command (const char *fmt, const eprintf_command_t *cmd)
{
int fs_len;
const char *seek;
str_t *str = str_create ();
for (seek = fmt; *seek; seek++){
if (*seek == '%'){
fs_len = put_command_special (str, seek, cmd);
seek += fs_len;
}
else
str_put_char (str, *seek);
}
return str_finished (str);
}
static void
substitute_addr (const char *fmt, address_t *addr, str_t *str)
{
int fs_len;
const char *seek;
for (seek = fmt; *seek; seek++){
if (*seek == '%'){
fs_len = put_addr_special (str, seek, addr);
seek += fs_len;
}
else
str_put_char (str, *seek);
}
}
static void
substitute_addr_desc (const char *fmt, str_t *str)
{
int fs_len;
const char *seek;
for (seek = fmt; *seek; seek++){
if (*seek == '%'){
fs_len = put_addr_desc_special (str, seek);
seek += fs_len;
}
else
str_put_char (str, *seek);
}
}
static char *
substitute_key (const char *fmt, struct key *key, int meta)
{
str_t *str = str_create ();
int fs_len;
const char *seek;
for (seek = fmt; *seek; seek++){
if (*seek == '%'){
fs_len = put_key_special (str, seek, key, meta);
seek += fs_len;
}
else
str_put_char (str, *seek);
}
return str_finished (str);
}
static void
substitute_box (const char *fmt, const char *box, str_t *str)
{
const char *seek;
int fs_len;
for (seek = fmt; *seek; seek++){
if (*seek == '%'){
fs_len = put_box_special (str, seek, box);
seek += fs_len;
}
else
str_put_char (str, *seek);
}
}
static void
substitute_mime (const char *fmt, mime_t *mime, str_t *str)
{
const char *seek;
int fs_len;
for (seek = fmt; *seek; seek++){
if (*seek == '%'){
fs_len = put_mime_special (str, seek, mime);
seek += fs_len;
}
else
str_put_char (str, *seek);
}
}
static char *
substitute_rstring (const char *fmt, rstring_t *values)
{
str_t *str = str_create ();
int fs_len;
const char *seek;
for (seek = fmt; *seek; seek++){
if (*seek == '%'){
fs_len = put_rstring_special (str, seek, values);
seek += fs_len;
}
else
str_put_char (str, *seek);
}
return str_finished (str);
}
/****************************************************************************
* INTERFACE FUNCTIONS
****************************************************************************/
void
eprintf_mail_str (const char *fmt, mail_t *mail, str_t *str)
{
str_clear (str);
substitute_mail (fmt, mail, str);
}
char *
eprintf_mail (const char *fmt, mail_t *mail)
{
str_t *str = str_create ();
substitute_mail (fmt, mail, str);
return str_finished (str);
}
void
eprintf_mail_desc (const char *fmt, str_t *str)
{
str_clear (str);
substitute_mail_desc (fmt, str);
}
char *
eprintf_command (const char *fmt, const eprintf_command_t *cmd)
{
char *result;
result = substitute_command (fmt, cmd);
return result;
}
void
eprintf_addr_str (const char *fmt, address_t *addr, str_t *str)
{
str_clear (str);
substitute_addr (fmt, addr, str);
}
void
eprintf_addr_desc (const char *fmt, str_t *str)
{
str_clear (str);
substitute_addr_desc (fmt, str);
}
char *
eprintf_key (const char *fmt, struct key *key, int meta)
{
char *result;
result = substitute_key (fmt, key, meta);
return result;
}
void
eprintf_box_str (const char *fmt, const char *box, str_t *str)
{
str_clear (str);
substitute_box (fmt, box, str);
}
void
eprintf_mime_str (const char *fmt, mime_t *mime, str_t *str)
{
str_clear (str);
substitute_mime (fmt, mime, str);
}
char *
eprintf_rstring (const char *fmt, rstring_t *values)
{
char *result;
result = substitute_rstring (fmt, values);
return result;
}
/****************************************************************************
* INTERFACE CLASS BODIES
****************************************************************************/
/****************************************************************************
*
* END MODULE eprintf.c
*
****************************************************************************/
syntax highlighted by Code2HTML, v. 0.9.1