/*
* WMMail - Window Maker Mail
*
* Copyright (c) 1996, 1997, 1998 Per Liden
* Copyright (c) 1997, 1998 Bryan Chan
*
* 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* properties.c: routines that read libPL-style properties (some stolen
* code courtesy of Peter Bentley's Malaprop
* (http://www.sorted.org/~pete/wmaker):
*
* Copyright (c) 1998 Peter Bentley (pete@sorted.org)
*
* Permission to use, copy, modify, distribute, and sell this software
* and its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice and this permission notice
* appear in all copies of the software and related documentation
*
* THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
* EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
* WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
*
* IN NO EVENT SHALL PETER BENTLEY BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
* INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT
* ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY,
* ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
* SOFTWARE.
*
* $Id: properties.c,v 1.1 2000/07/02 20:38:01 bryan.chan Exp $
*
*/
#include <stdlib.h>
#include <strings.h>
#include <pwd.h>
#include <proplist.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "wmmail.h"
#include "wmutil.h"
#include "list.h"
#define GET_ENTRY(x,y,z) { proplist_t sub_key = PLMakeString(z); \
y = PLGetDictionaryEntry(x, sub_key); \
PLRelease(sub_key); }
/* function prototypes */
static proplist_t domain_load(char *);
static int get_boolean(proplist_t, proplist_t, int *);
static int get_coord(proplist_t, proplist_t, int *, int *);
static int get_int(proplist_t, proplist_t, int *);
static int get_num_of_msg_mode(proplist_t, proplist_t, int *);
static int get_animations(proplist_t, proplist_t);
static int get_animation(proplist_t, proplist_t, int);
static void anim_add_frame(int, char *);
static void anim_load_frame(XpmIcon *, char *);
static int get_mailboxes(proplist_t, proplist_t);
static int init_mailbox(Mailbox *, proplist_t);
/* parse the WMMail domain; what's a cleaner, simpler way to do this? */
int parse_gnustep_domain(char *path)
{
unsigned int i, number_of_keys;
proplist_t keys, key, value;
proplist_t domain = domain_load(path);
char *str;
if (domain != NULL && PLIsDictionary(domain))
{
if ( (keys = PLGetAllDictionaryKeys(domain)) != NULL )
{
number_of_keys = PLGetNumberOfElements(keys);
for (i = 0; i < number_of_keys; i++)
{
key = PLGetArrayElement(keys, i);
value = PLGetDictionaryEntry(domain, key);
str = PLGetString(key);
if (PLIsDictionary(value))
{
if (!strcasecmp("Animations", str))
{
get_animations(key, value);
}
else
croak("unrecognized dictionary \"%s\" ignored", str);
}
else if (PLIsString(value))
{
if (!strcasecmp("DisableBeep", str))
{
get_boolean(key, value, &use_beep);
use_beep = ! use_beep; /* if yes, then don't use beep */
}
else if (!strcasecmp("DoubleClickTime", str))
{
get_int(key, value, &double_click_time);
}
else if (!strcasecmp("DisplayEachMailbox", str))
{
get_boolean(key, value, &display_names);
}
else if (!strcasecmp("DisplayMessageCount", str))
{
get_num_of_msg_mode(key, value, &num_of_msg_mode);
}
else if (!strcasecmp("DisplayColor", str))
{
wmmail_color = wstrdup(PLGetString(value));
}
else if (!strcasecmp("DisplayFont", str))
{
wmmail_font = XLoadFont(disp, PLGetString(value));
}
else if (!strcasecmp("ExecuteOnNew", str))
{
exec_on_new = wstrdup(PLGetString(value));
}
else if (!strcasecmp("ExecuteOnClick", str))
{
exec_on_click = wstrdup(PLGetString(value));
}
else
croak("unrecognized key \"%s\" ignored", str);
}
else if (PLIsArray(value))
{
if (!strcasecmp("Mailboxes", str))
{
get_mailboxes(key, value);
}
else if (!strcasecmp("DisplayLocation", str))
{
get_coord(key, value, &num_of_msg_x, &num_of_msg_y);
}
else
croak("unrecognized array \"%s\" ignored", str);
}
wfree(str);
}
}
return True;
}
else
{
croak("defaults domain %s corrupted", path);
return False;
}
}
/* load the specified domain from disk */
static proplist_t domain_load(char *path)
{
proplist_t list = NULL;
if (path)
{
list = PLGetProplistWithPath(path);
wfree((void *) path);
}
return list;
}
/* get a boolean value from a property list entry */
static int get_boolean(proplist_t key, proplist_t value, int *addr)
{
static int data;
char *s;
if (!PLIsString(value))
{
croak("wrong option format for key \"%s\"; boolean expected",
PLGetString(key));
return False;
}
s = PLGetString(value);
if (!strcasecmp("Yes", s))
data = True;
else if (!strcasecmp("No", s))
data = False;
else
{
croak("wrong option format for key \"%s\"; boolean expected",
PLGetString(key));
return False;
}
wfree(s);
if (addr)
*addr = data;
return True;
}
/* get a coordinate from a property list entry */
static int get_coord(proplist_t key, proplist_t value, int *addr_x, int *addr_y)
{
int dimensions, data[2], i;
if (!PLIsArray(value))
{
croak("wrong option format for key \"%s\"; coordinates expected",
PLGetString(key));
return False;
}
if (( dimensions = PLGetNumberOfElements(value) ) != 2)
{
croak("wrong option format for key \"%s\"; coordinates expected",
PLGetString(key));
return False;
}
for (i = 0; i < dimensions; i++)
{
proplist_t element = PLGetArrayElement(value, i);
if (!PLIsString(element))
{
croak("wrong option format for key \"%s\"; coordinates expected",
PLGetString(key));
return False;
}
if (sscanf(PLGetString(element), "%i", &data[i]) != 1)
{
croak("integer pair expected for coordinates in key \"%s\"",
PLGetString(key));
return False;
}
}
*addr_x = data[0];
*addr_y = data[1];
return True;
}
/* get an integer from a property list entry */
static int get_int(proplist_t key, proplist_t value, int *addr)
{
static int data;
char *s;
if (!PLIsString(value))
{
croak("wrong option format for key \"%s\"; integer expected",
PLGetString(key));
return False;
}
s = PLGetString(value);
if (sscanf(s, "%i", &data) != 1)
{
croak("cannot convert \"%s\" to integer for key \"%s\"",
s, PLGetString(key));
return False;
}
if (addr)
*addr = data;
return True;
}
static int get_num_of_msg_mode(proplist_t key, proplist_t value, int *addr)
{
static int data;
char *s;
if (!PLIsString(value))
{
croak("wrong option format for key \"%s\"; expected \"NewOnly\", "
"\"TotalOnly\", \"NewOverTotal\", or \"None\"",
PLGetString(key));
return False;
}
s = PLGetString(value);
if (!strcasecmp("None", s))
data = SHOW_NONE;
else if (!strcasecmp("NewOverTotal", s))
data = SHOW_NEW_OVER_TOTAL;
else if (!strcasecmp("NewOnly", s))
data = SHOW_NEW_ONLY;
else if (!strcasecmp("TotalOnly", s))
data = SHOW_TOTAL_ONLY;
else
{
croak("wrong option format for key \"%s\"; expected \"NewOnly\", "
"\"TotalOnly\", \"NewOverTotal\", or \"None\"",
PLGetString(key));
return False;
}
if (addr)
*addr = data;
return True;
}
/* ANIMATIONS */
static int get_animations(proplist_t key, proplist_t value)
{
proplist_t animation_properties[3];
proplist_t delay_key, delay_value;
proplist_t frame_key, frame_value;
GET_ENTRY(value, animation_properties[NO_MAIL], "Empty");
GET_ENTRY(value, animation_properties[OLD_MAIL], "Old");
GET_ENTRY(value, animation_properties[NEW_MAIL], "New");
delay_key = PLMakeString("Delay");
frame_key = PLMakeString("Frames");
if (animation_properties[NO_MAIL] != NULL)
{
delay_value = PLGetDictionaryEntry(animation_properties[NO_MAIL],
delay_key);
if (delay_value != NULL)
{
get_int(delay_key, delay_value, &anim_speed[NO_MAIL]);
anim_speed[NO_MAIL] *= 100;
}
frame_value = PLGetDictionaryEntry(animation_properties[NO_MAIL],
frame_key);
if (frame_value != NULL)
get_animation(frame_key, frame_value, NO_MAIL);
}
if (animation_properties[OLD_MAIL] != NULL)
{
delay_value = PLGetDictionaryEntry(animation_properties[OLD_MAIL],
delay_key);
if (delay_value != NULL)
{
get_int(delay_key, delay_value, &anim_speed[OLD_MAIL]);
anim_speed[OLD_MAIL] *= 100;
}
frame_value = PLGetDictionaryEntry(animation_properties[OLD_MAIL],
frame_key);
if (frame_value != NULL)
get_animation(frame_key, frame_value, OLD_MAIL);
}
if (animation_properties[NEW_MAIL] != NULL)
{
delay_value = PLGetDictionaryEntry(animation_properties[NEW_MAIL],
delay_key);
if (delay_value != NULL)
{
get_int(delay_key, delay_value, &anim_speed[NEW_MAIL]);
anim_speed[NEW_MAIL] *= 100;
}
frame_value = PLGetDictionaryEntry(animation_properties[NEW_MAIL],
frame_key);
if (frame_value != NULL)
get_animation(frame_key, frame_value, NEW_MAIL);
}
PLRelease(delay_key);
PLRelease(frame_key);
return True;
}
static int get_animation(proplist_t key, proplist_t frames, int type)
{
int i, number_of_frames;
if (!PLIsArray(frames))
{
croak("wrong option format for key \"%s\"; array expected",
PLGetString(key));
return False;
}
number_of_frames = PLGetNumberOfElements(frames);
for (i = 0; i < number_of_frames; i++)
{
char *s = PLGetString(PLGetArrayElement(frames, i));
anim_add_frame(type, s);
wfree(s);
}
return True;
}
static void anim_add_frame(int which, char *path)
{
XpmIcon *current;
if (animations[which] == NULL)
{
animations[which] = (XpmIcon *) wmalloc(sizeof(XpmIcon));
current = animations[which];
}
else
{
for (current = animations[which];
current->next != animations[which]; /* until wrapped around */
current = current->next);
current->next = (XpmIcon *) wmalloc(sizeof(XpmIcon));
current = current->next;
}
anim_load_frame(current, path);
current->next = animations[which]; /* make a looping animation */
current->text_cycle = -1; /* don't cycle text */
}
static void anim_load_frame(XpmIcon *anim, char *path)
{
int ret;
anim->attributes.valuemask = (XpmExactColors | XpmCloseness);
anim->attributes.exactColors = FALSE;
anim->attributes.closeness = 40000;
ret = XpmReadFileToPixmap(disp, root, path, &anim->pixmap, &anim->mask,
&anim->attributes);
switch(ret)
{
case XpmSuccess:
break;
case XpmColorError:
case XpmColorFailed:
croak("not enough free colours loading '%s'", path);
break;
case XpmOpenFailed:
croak("cannot open '%s'", path);
break;
case XpmFileInvalid:
croak("invalid XPM file '%s'", path);
break;
case XpmNoMemory:
croak("not enough free memory loading '%s'", path);
break;
default:
croak("unknown error (%d) loading '%s'", ret, path);
break;
}
if (ret < 0)
exit(-1);
if (anim->mask == 0)
{
croak("XPM file '%s' does not have a transparent colour");
exit(-1);
}
}
/* MAILBOXES */
static int get_mailboxes(proplist_t key, proplist_t value)
{
int i,
number_of_mailboxes = PLGetNumberOfElements(value);
Mailbox *mailbox;
proplist_t mailbox_definition;
if (number_of_mailboxes > 0)
{
for (i = 0; i < number_of_mailboxes; i++)
{
mailbox_definition = PLGetArrayElement(value, i);
if (PLIsDictionary(mailbox_definition))
{
mailbox = (Mailbox *) wmalloc(sizeof(Mailbox));
/* parse mailbox definition; destroy the mailbox if it is bad */
if (init_mailbox(mailbox, mailbox_definition))
{
#ifdef DEBUG
croak("mailbox \"%s\" added", mailbox->name);
#endif
mailbox_list = list_cons(mailbox, mailbox_list);
mailbox_count = list_length(mailbox_list);
}
else
{
croak("mailbox \"%s\" ignored", (mailbox->name ? mailbox->name : ""));
wfree(mailbox->execute_on_update);
wfree(mailbox->name);
wfree(mailbox);
}
}
else
{
/* skip this mailbox if its definition is corrupt */
croak("wrong option format for key \"%s\"; mailbox definition "
"expected", PLGetString(key));
}
}
}
return True;
}
static int init_mailbox(Mailbox *mailbox, proplist_t mailbox_definition)
{
proplist_t mailbox_name,
mailbox_type,
execute_on_update,
update_interval;
char *mailbox_type_text;
mailbox->status = NO_MAIL;
mailbox->total_mail_count = 0;
mailbox->new_mail_count = 0;
mailbox->size = -1;
mailbox->last_update = 0;
GET_ENTRY(mailbox_definition, mailbox_name, "Name");
if (mailbox_name != NULL)
{
if (!PLIsString(mailbox_name))
{
croak("wrong option format for key \"Name\"; string expected");
return False;
}
else
mailbox->name = PLGetString(mailbox_name);
}
else
{
croak("mailbox missing key \"Name\"; ignored");
return False;
}
GET_ENTRY(mailbox_definition, mailbox_type, "Type");
if (mailbox_type != NULL)
{
if (!PLIsString(mailbox_type))
{
croak("wrong option format for key \"Type\"; mailbox type expected");
return False;
}
else
mailbox_type_text = PLGetString(mailbox_type);
#ifdef MBOX_SUPPORT
if (!strcasecmp(mailbox_type_text, "mbox"))
mailbox->type = TYPE_MBOX;
else
#endif
#ifdef MH_SUPPORT
if (!strcasecmp(mailbox_type_text, "mh"))
mailbox->type = TYPE_MH;
else
#endif
#ifdef MAILDIR_SUPPORT
if (!strcasecmp(mailbox_type_text, "maildir"))
mailbox->type = TYPE_MAILDIR;
else
#endif
#ifdef POP3_SUPPORT
if (!strcasecmp(mailbox_type_text, "pop3"))
mailbox->type = TYPE_POP3;
else
#endif
#ifdef IMAP_SUPPORT
if (!strcasecmp(mailbox_type_text, "imap"))
mailbox->type = TYPE_IMAP;
else
#endif
{
croak("unknown mailbox type \"%s\"; expected: "
#ifdef MBOX_SUPPORT
"\"mbox\", "
#endif
#ifdef MH_SUPPORT
"\"mh\", "
#endif
#ifdef MAILDIR_SUPPORT
"\"MailDir\", "
#endif
#ifdef POP3_SUPPORT
"\"POP3\", "
#endif
#ifdef IMAP_SUPPORT
"\"IMAP\""
#endif
, mailbox_type_text);
return False;
}
}
else
{
croak("mailbox \"%s\" missing key \"Type\"; ignored", mailbox->name);
return False;
}
GET_ENTRY(mailbox_definition, execute_on_update, "ExecuteOnUpdate");
if (execute_on_update != NULL)
{
if (!PLIsString(execute_on_update))
{
croak("wrong option format for key \"ExecuteOnUpdate\"; string expected");
return False;
}
else
mailbox->execute_on_update = PLGetString(execute_on_update);
}
else
mailbox->execute_on_update = NULL;
GET_ENTRY(mailbox_definition, update_interval, "UpdateInterval");
{
proplist_t label = PLMakeString("UpdateInterval");
if (update_interval == NULL ||
!get_int(label, update_interval, &mailbox->update_interval))
{
croak("mailbox \"%s\" missing key \"UpdateInterval\"; %d assumed",
mailbox->name, DEFAULT_INTERVAL);
mailbox->update_interval = DEFAULT_INTERVAL;
}
PLRelease(label);
}
GET_ENTRY(mailbox_definition, mailbox->options, "Options");
if (mailbox->options == NULL)
{
croak("mailbox \"%s\" missing key \"Options\"; ignored", mailbox->name);
return False;
}
else if (!PLIsDictionary(mailbox->options))
{
croak("wrong option format for key \"Options\"; dictionary expected");
return False;
}
return True;
}
syntax highlighted by Code2HTML, v. 0.9.1