Index: mailjam/cli.py
===================================================================
--- mailjam/cli.py	(revision 23)
+++ mailjam/cli.py	(revision 23)
@@ -0,0 +1,135 @@
+# -*- coding: utf-8 -*-
+
+"""
+The mailjam project - cli.py
+
+This file is released under the BSD license, see LICENSE for
+more information.
+
+Francisco de Borja Lopez Rio - <borja@codigo23.net>
+Soluciones Informaticas Codigo23 S.L.U. - http://codigo23.net
+"""
+
+import os, cmd, xmlrpclib
+from mailjam.config import CLIClientConfig
+
+class CLIClient(cmd.Cmd):    
+
+    def __init__(self, configfile=None, *args, **kwargs):
+        cmd.Cmd.__init__(self)
+        cli_config = CLIClientConfig(configfile=configfile)
+        cli_config.load()
+        self.config = cli_config.config
+        self.rpc = xmlrpclib.ServerProxy(self.config['server']['uri'])
+        self.prompt = "mailjam-cli > "
+        self.intro = "Welcome to Mailjam's CLI client - type help for a list of commands"
+        self._history = []
+        
+    def do_history(self, line):
+        """
+        history
+        Show a list of recently executed commands
+
+        Alias: h
+        """
+        if not self._history:
+            print 'No history data available'
+        else:
+            for i in self._history:
+                print self._history.index(i), ' - ', i
+                
+    def do_h(self, line):
+        """
+        h
+        Alias for the history command. To learn more type:
+
+        help history
+        """
+        self.do_history(line)
+    
+    def do_add_mailing_list(self, line):
+        """
+        add_mailing_list [name] address
+        Add a new mailing list to the remote mailjam server. You have to
+        provide a valid email address for the mailing list to be added. If no
+        name is provided, the address itself will be used.
+
+        Alias: aml
+        """
+        if not line:
+            print 'usage: add_mailing_list [name] address'
+        else:
+            params = line.split(' ')
+            address = params.pop()
+            if not params:
+                name = address
+            else:
+                name = ' '.join(params)
+            info = {'name': name, 'address': address, 'members': {},
+                    'configfile': self.config['server']['configfile']}
+            result = self.rpc.lists.add(info)
+            print result
+
+    def do_aml(self, line):
+        """
+        aml [name] address
+        Alias for the add_mailing_list command. To learn more type:
+
+        help add_mailing_list
+        """
+        self.do_add_mailing_list(line)
+
+    def do_add_mailing_list_member(self, line):
+        """
+        add_mailing_list_member member_address list_address
+        Add a new member to a given mailing list. You have to provide valid
+        email addresses for both the member and the list. The mailing list
+        must be handled by the remote mailjam server for this operation to
+        work.
+
+        Alias: amlm
+        """
+        pass
+
+    def do_show_mailing_list_members(self, line):
+        """
+        show_mailing_list_members address
+        """
+        pass
+    
+    def do_EOF(self, line):
+        return True
+
+    def precmd(self, line):
+        # save the commands to the history, if it is enabled in the config file
+        if self.config['history']['enabled']:            
+            self._history.append(line)
+        return line
+    
+    def postloop(self):
+        # save history to a file, if it is enabled in the config file.
+        if self.config['history']['enabled']:
+            history_file_name = self.config['history']['path']
+            if '~' in history_file_name:
+                # we have to replace that with the proper home path
+                # FIXME: we should call some "sanitize" function here, to
+                # get rid of dangerous paths in the file name
+                home = os.path.expanduser("~")
+                history_file_name = history_file_name.replace('~', home)
+            if not os.path.exists(history_file_name):
+                try:
+                    os.makedirs(os.path.dirname(history_file_name))
+                except OSError, e:
+                    # If the dir already exists do not complain, if it is
+                    # any other error, raise the exception
+                    if e.errno != errno.EEXIST:
+                        raise
+            history_file = open(history_file_name, 'a')
+            for i in self._history:
+                if 'EOF' not in i:
+                    history_file.write(i+'\n')
+            history_file.close()
+        print 'Bye!'
+
+    def emptyline(self):
+        pass
Index: mailjam/config.py
===================================================================
--- mailjam/config.py	(revision 20)
+++ mailjam/config.py	(revision 23)
@@ -89,4 +89,5 @@
         return self.config[section]
 
+
 class MTAClientConfig(DaemonConfig):
     @property
@@ -97,4 +98,14 @@
     def sections(self):
         return ['server', 'archive']
+
+
+class CLIClientConfig(DaemonConfig):
+    @property
+    def default_filename(self):
+        return 'mailjam-cli.conf'
+
+    @property
+    def sections(self):
+        return ['server', 'archive', 'history']
 
 
Index: mailjam/daemon.py
===================================================================
--- mailjam/daemon.py	(revision 20)
+++ mailjam/daemon.py	(revision 23)
@@ -163,6 +163,8 @@
     def _listMethods(self):
         public_methods = []
-        public_methods += ['lists.'+i for i in dir(MailingListXMLRPC) if '_' not in i]
-        public_methods += ['members.'+i for i in dir(MemberXMLRPC) if '_' not in i]
+        public_methods += ['lists.'+i for i in dir(MailingListXMLRPC) \
+                           if '_' not in i]
+        public_methods += ['members.'+i for i in dir(MemberXMLRPC) \
+                           if '_' not in i]
         return public_methods
 
@@ -177,7 +179,11 @@
         self.mailjam.load()
     def add(self, info={}):
-        self.mailjam.add_mailing_list(info)
+        try:
+            self.mailjam.add_mailing_list(info)
+        except IndexError, e:
+            return str(e)
+        return 'Added mailing list ' + info['address']  
     def addresses(self):
-        return self.mailjam.mailings_addresses    
+        return self.mailjam.mailings_addresses
 
 
@@ -187,5 +193,9 @@
         self.mailjam.load()
     def add(self, member_addr=None, list_addr=None):
-        self.mailjam.add_mailing_member(member_addr, list_addr)
+        try:
+            self.mailjam.add_mailing_member(member_addr, list_addr)
+        except IndexError, e:
+            return str(e)
+        return 'Added member ' + member_addr + ' to ' + list_addr
     def list(self, mailing):
         if mailing in self.mailjam.mailings_addresses:
Index: mailjam/models.py
===================================================================
--- mailjam/models.py	(revision 16)
+++ mailjam/models.py	(revision 23)
@@ -33,5 +33,5 @@
     def _validate_address(self, address):
         if not validate_email_address(address):
-            raise ValueError(address, ' is not a valid email address')
+            raise ValueError(str(address) + ' is not a valid email address')
         return address
 
@@ -63,5 +63,5 @@
     def _validate_member_object(self, member=None):
         if not isinstance(member, Member):
-            raise TypeError(member, ' is not a valid Member instance')
+            raise TypeError(str(member) + ' is not a valid Member instance')
         return member
 
@@ -72,5 +72,5 @@
     def _validate_member_by_address(self, address=None):
         if not validate_email_address(address):
-            raise ValueError(address, ' is not a valid email address')
+            raise ValueError(str(address) + ' is not a valid email address')
         return address in self.members_addresses()
 
