/* * 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 #include #include #include #include #include #include #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; }