Index: ChangeLog
===================================================================
--- ChangeLog	(revision fd93b41172517bb322cb0ade63533aed2cc51429)
+++ ChangeLog	(revision 38cf544c320814f53070c768b4974c2786a024f4)
@@ -82,5 +82,7 @@
 	  WORK yet
 	Removed a bit of faim code that allowed commands to be executed.
-	
+	The 'B' key is now bound to 'alist'
+	Added the 'startup' and 'unstartup' commands
+	The $HOME/.owl directory is created on startup if it does not exist
 	
 1.2.8
Index: buddylist.c
===================================================================
--- buddylist.c	(revision aa5f725832e087e7a8c053b6d238f21fae14500b)
+++ buddylist.c	(revision 38cf544c320814f53070c768b4974c2786a024f4)
@@ -72,6 +72,4 @@
 
 void owl_buddylist_clear(owl_buddylist *b) {
-  int i, j;
-
   owl_list_free_all(&(b->buddies), owl_free);
   owl_list_create(&(b->buddies));
Index: commands.c
===================================================================
--- commands.c	(revision fd93b41172517bb322cb0ade63533aed2cc51429)
+++ commands.c	(revision 38cf544c320814f53070c768b4974c2786a024f4)
@@ -159,4 +159,17 @@
 	      "are used print the value of all variables.\n"),
 
+  OWLCMD_ARGS("startup", owl_command_startup, OWL_CTX_ANY,
+	      "run a command and set it to be run at every Owl startup",
+	      "startup <commands> ...",
+	      "Everything on the command line after the startup command\n"
+	      "is executed as a normal owl command and is also placed in\n"
+	      "a file so that the command is executed every time owl\n"
+	      "is started"),
+
+  OWLCMD_ARGS("unstartup", owl_command_unstartup, OWL_CTX_ANY,
+	      "remove a command from the list of those to be run at Owl startup",
+	      "unstartup <commands> ...",
+	      ""),
+
   OWLCMD_VOID("version", owl_command_version, OWL_CTX_ANY,
 	      "print the version of the running owl", "", ""),
@@ -201,6 +214,6 @@
 	      "add a buddy to a buddylist",
 	      "addbuddy aim <screenname>",
-	      "Add the named buddy to your buddylist.  Eventually other protocols,"
-	      "such as zephyr, will also be able to use this command.  For now the"
+	      "Add the named buddy to your buddylist.  Eventually other protocols,\n"
+	      "such as zephyr, will also be able to use this command.  For now the\n"
 	      "only available protocol is 'aim', specified as the first argument."),
 
@@ -208,7 +221,7 @@
 	      "delete a buddy from a buddylist",
 	      "delbuddy aim <screenname>",
-	      "Delete the named buddy to your buddylist.  Eventually other protocols,"
-	      "such as zephyr, will also be able to use this command.  For now the"
-	      "only available protocol is 'aim', specified as the first argument."),
+	      "Delete the named buddy to your buddylist.  Eventually other protocols,\n"
+	      "such as zephyr, will also be able to use this command.  For now the\n"
+	      "only available protocol is 'aim', specified as the first argument.\n"),
 
   OWLCMD_ARGS("smartzpunt", owl_command_smartzpunt, OWL_CTX_INTERACTIVE,
@@ -909,4 +922,51 @@
   owl_aim_delbuddy(argv[2]);
   owl_function_makemsg("%s deleted as AIM buddy for %s", argv[2], owl_global_get_aim_screenname(&g));
+
+  return(NULL);
+}
+
+char *owl_command_startup(int argc, char **argv, char *buff)
+{
+  char *ptr;
+
+  if (argc<2) {
+    owl_function_makemsg("usage: %s <commands> ...", argv[0]);
+    return(NULL);
+  }
+
+  /* we'll be pedantic here, just in case this command gets another name
+   *  (or is aliased) start after the first space on the line
+   */
+  ptr=strchr(buff, ' ');
+  if (!ptr) {
+    owl_function_makemsg("Parse error finding command for startup");
+    return(NULL);
+  }
+
+  owl_function_command(ptr+1);
+  owl_function_addstartup(ptr+1);
+
+  return(NULL);
+}
+
+char *owl_command_unstartup(int argc, char **argv, char *buff)
+{
+  char *ptr;
+
+  if (argc<2) {
+    owl_function_makemsg("usage: %s <commands> ...", argv[0]);
+    return(NULL);
+  }
+
+  /* we'll be pedantic here, just in case this command gets another name
+   *  (or is aliased) start after the first space on the line
+   */
+  ptr=strchr(buff, ' ');
+  if (!ptr) {
+    owl_function_makemsg("Parse error finding command for unstartup");
+    return(NULL);
+  }
+
+  owl_function_delstartup(ptr+1);
 
   return(NULL);
Index: functions.c
===================================================================
--- functions.c	(revision aa5f725832e087e7a8c053b6d238f21fae14500b)
+++ functions.c	(revision 38cf544c320814f53070c768b4974c2786a024f4)
@@ -2895,2 +2895,52 @@
   printf("\033[1t");
 }
+
+/* Add the specified command to the startup file.  Eventually this
+ * should be clever, and rewriting settings that will obviosly
+ * override earlier settings with 'set' 'bindkey' and 'alias'
+ * commands.  For now though we just append to the startupfile.
+ */
+void owl_function_addstartup(char *buff)
+{
+  FILE *file;
+  char *filename;
+
+  filename=owl_sprintf("%s/%s", owl_global_get_homedir(&g), OWL_STARTUP_FILE);
+  file=fopen(filename, "a");
+  owl_free(filename);
+  if (!file) {
+    owl_function_makemsg("Error opening startupfile for new command");
+    return;
+  }
+  fprintf(file, "%s\n", buff);
+  fclose(file);
+}
+
+/* Remove the specified command from the startup file. */
+void owl_function_delstartup(char *buff)
+{
+  char *filename;
+  filename=owl_sprintf("%s/%s", owl_global_get_homedir(&g), OWL_STARTUP_FILE);
+  owl_util_file_deleteline(filename, buff, 1);
+  owl_free(filename);
+}
+
+void owl_function_execstartup(void)
+{
+  FILE *file;
+  char *filename;
+  char buff[LINE];
+
+  filename=owl_sprintf("%s/%s", owl_global_get_homedir(&g), OWL_STARTUP_FILE);
+  file=fopen(filename, "r");
+  owl_free(filename);
+  if (!file) {
+    /* just fail silently if it doesn't exist */
+    return;
+  }
+  while (fgets(buff, LINE, file)!=NULL) {
+    buff[strlen(buff)-1]='\0';
+    owl_function_command(buff);
+  }
+  fclose(file);
+}
Index: keys.c
===================================================================
--- keys.c	(revision aa5f725832e087e7a8c053b6d238f21fae14500b)
+++ keys.c	(revision 38cf544c320814f53070c768b4974c2786a024f4)
@@ -242,4 +242,5 @@
   BIND_CMD("i",   "info",             "");
   BIND_CMD("l",   "blist",            "");
+  BIND_CMD("B",   "alist",            "");
   BIND_CMD("M",   "pop-message",      "");
   BIND_CMD("T",   "delete trash",     "mark all 'trash' messages for deletion");
Index: owl.c
===================================================================
--- owl.c	(revision 3abf28bfbedff7d4c809523f93b98d6fd70d120e)
+++ owl.c	(revision 38cf544c320814f53070c768b4974c2786a024f4)
@@ -22,4 +22,5 @@
 #include <sys/param.h>
 #include <sys/types.h>
+#include <sys/stat.h>
 #include "owl.h"
 
@@ -37,4 +38,5 @@
   time_t nexttime, now;
   struct tm *today;
+  char *dir;
 
   argcsave=argc;
@@ -123,4 +125,5 @@
     init_pair(OWL_COLOR_WHITE,   COLOR_WHITE,   -1);
   }
+
     
   /* owl init */
@@ -128,5 +131,9 @@
   if (debug) owl_global_set_debug_on(&g);
   owl_global_set_startupargs(&g, argcsave, argvsave);
-  owl_context_set_readconfig(owl_global_get_context(&g));
+
+  /* create the owl directory, in case it does not exist */
+  dir=owl_sprintf("%s/%s", owl_global_get_homedir(&g), OWL_CONFIG_DIR);
+  mkdir(dir, S_IRWXU);
+  owl_free(dir);
 
   /* set the tty, either from the command line, or by figuring it out */
@@ -138,5 +145,4 @@
 
   /* setup the default filters */
-
   /* the personal filter will need to change again when AIM chat's are
    *  included.  Also, there should be an %aimme% */
@@ -191,5 +197,10 @@
   owl_view_create(owl_global_get_current_view(&g), f);
 
+  /* process the startup file */
+  owl_function_execstartup();
+
+
   /* read the config file */
+  owl_context_set_readconfig(owl_global_get_context(&g));
   ret=owl_readconfig(configfile);
   if (ret) {
Index: owl.h
===================================================================
--- owl.h	(revision aa5f725832e087e7a8c053b6d238f21fae14500b)
+++ owl.h	(revision 38cf544c320814f53070c768b4974c2786a024f4)
@@ -19,4 +19,7 @@
 #define OWL_DEBUG 0
 #define OWL_DEBUG_FILE "/var/tmp/owldebug"
+
+#define OWL_CONFIG_DIR "/.owl"           /* this is relative to the user's home directory */
+#define OWL_STARTUP_FILE "/.owl/startup"   /* this is relative to the user's home directory */
 
 #define OWL_FMTEXT_ATTR_NONE      0
Index: owl_prototypes.h
===================================================================
--- owl_prototypes.h	(revision fd93b41172517bb322cb0ade63533aed2cc51429)
+++ owl_prototypes.h	(revision 38cf544c320814f53070c768b4974c2786a024f4)
@@ -61,4 +61,6 @@
 extern char *owl_command_addbuddy(int argc, char **argv, char *buff);
 extern char *owl_command_delbuddy(int argc, char **argv, char *buff);
+extern char *owl_command_startup(int argc, char **argv, char *buff);
+extern char *owl_command_unstartup(int argc, char **argv, char *buff);
 extern char *owl_command_dump(int argc, char **argv, char *buff);
 extern char *owl_command_next(int argc, char **argv, char *buff);
@@ -395,4 +397,7 @@
 extern void owl_function_xterm_raise(void);
 extern void owl_function_xterm_deiconify(void);
+extern void owl_function_addstartup(char *buff);
+extern void owl_function_delstartup(char *buff);
+extern void owl_function_execstartup(void);
 
 /* -------------------------------- global.c -------------------------------- */
@@ -740,4 +745,5 @@
 extern void owl_hack_animate();
 extern char *owl_util_stripnewlines(char *in);
+extern void owl_util_file_deleteline(char *filename, char *line, int backup);
 extern int owl_util_regtest(void);
 
Index: util.c
===================================================================
--- util.c	(revision 7c8060d018b54ba9d52b72390da9c589eefb1347)
+++ util.c	(revision 38cf544c320814f53070c768b4974c2786a024f4)
@@ -648,4 +648,76 @@
 }
 
+/* Delete the line matching "line" from the named file.  If no such
+ * line is found the file is left intact.  If backup==1 then create a
+ * backupfile containing the original contents.  This is an
+ * inefficient impelementation which reads the entire file into
+ * memory.
+ */
+void owl_util_file_deleteline(char *filename, char *line, int backup)
+{
+  char buff[LINE], *text;
+  char *backupfilename;
+  FILE *file, *backupfile;
+  int size, newline;
+
+  /* open the file for reading */
+  file=fopen(filename, "r");
+  if (!file) {
+    owl_function_makemsg("Error opening file %s", filename);
+    return;
+  }
+  
+  /* open the backup file for writing */
+  if (backup) {
+    backupfilename=owl_sprintf("%s.backup", filename);
+    backupfile=fopen(backupfilename, "w");
+    owl_free(backupfilename);
+    if (!backupfile) {
+      owl_function_makemsg("Error opening file %s for writing", backupfilename);
+      return;
+    }
+  }
+
+  /* we'll read the entire file into memory, minus the line we don't want and
+   * and at the same time create the backup file if necessary
+   */
+  text=owl_malloc(LINE);
+  strcpy(text, "");
+  size=LINE;
+  while (fgets(buff, LINE, file)!=NULL) {
+    /* strip the newline */
+    newline=0;
+    if (buff[strlen(buff)-1]=='\n') {
+      buff[strlen(buff)-1]='\0';
+      newline=1;
+    }
+    
+    /* if we don't match the line, add to saved text in memory */
+    if (strcasecmp(buff, line)) {
+      size+=LINE;
+      text=owl_realloc(text, size);
+      strcat(text, buff);
+      if (newline) strcat(text, "\n");
+    }
+
+    /* write to backupfile if necessary */
+    if (backup) fputs(buff, backupfile);
+  }
+  fclose(backupfile);
+  fclose(file);
+
+  /* now rewrite the original file from memory */
+  file=fopen(filename, "w");
+  if (!file) {
+    owl_function_makemsg("WARNING: Error opening %s for writing.  Use %s to restore.", filename, backupfilename);
+    owl_function_beep();
+    owl_free(line);
+    return;
+  }
+
+  fputs(text, file);
+  fclose(file);
+}
+
 /**************************************************************************/
 /************************* REGRESSION TESTS *******************************/
