More detailed errors from mixer-alsa
[disorder] / python / disorder.py.in
index 0f16c1a..36157a0 100644 (file)
@@ -276,7 +276,7 @@ class client:
   debug_proto = 0x0001
   debug_body = 0x0002
 
   debug_proto = 0x0001
   debug_body = 0x0002
 
-  def __init__(self):
+  def __init__(self, user=None, password=None):
     """Constructor for DisOrder client class.
 
     The constructor reads the configuration file, but does not connect
     """Constructor for DisOrder client class.
 
     The constructor reads the configuration file, but does not connect
@@ -294,6 +294,8 @@ class client:
     self.config = { 'collections': [],
                     'username': pw.pw_name,
                     'home': _dbhome }
     self.config = { 'collections': [],
                     'username': pw.pw_name,
                     'home': _dbhome }
+    self.user = user
+    self.password = password
     home = os.getenv("HOME")
     if not home:
       home = pw.pw_dir
     home = os.getenv("HOME")
     if not home:
       home = pw.pw_dir
@@ -327,8 +329,10 @@ class client:
       sys.stderr.write("\n")
       sys.stderr.flush()
 
       sys.stderr.write("\n")
       sys.stderr.flush()
 
-  def connect(self):
-    """Connect to the DisOrder server and authenticate.
+  def connect(self, cookie=None):
+    """c.connect(cookie=None)
+
+    Connect to the DisOrder server and authenticate.
 
     Raises communicationError if connection fails and operationError if
     authentication fails (in which case disconnection is automatic).
 
     Raises communicationError if connection fails and operationError if
     authentication fails (in which case disconnection is automatic).
@@ -339,6 +343,9 @@ class client:
 
     Other operations automatically connect if we're not already
     connected, so it is not strictly necessary to call this method.
 
     Other operations automatically connect if we're not already
     connected, so it is not strictly necessary to call this method.
+
+    If COOKIE is specified then that is used to log in instead of
+    the username/password.
     """
     if self.state == 'disconnected':
       try:
     """
     if self.state == 'disconnected':
       try:
@@ -368,11 +375,27 @@ class client:
           s.connect(self.who)
         self.w = s.makefile("wb")
         self.r = s.makefile("rb")
           s.connect(self.who)
         self.w = s.makefile("wb")
         self.r = s.makefile("rb")
-        (res, challenge) = self._simple()
-        h = sha.sha()
-        h.update(self.config['password'])
-        h.update(binascii.unhexlify(challenge))
-        self._simple("user", self.config['username'], h.hexdigest())
+        (res, details) = self._simple()
+        (protocol, algo, challenge) = _split(details)
+        if protocol != '2':
+          raise communicationError(self.who,
+                                   "unknown protocol version %s" % protocol)
+        if cookie is None:
+          if self.user is None:
+            user = self.config['username']
+          else:
+            user = self.user
+          if self.password is None:
+            password = self.config['password']
+          else:
+            password = self.password
+          # TODO support algorithms other than SHA-1
+          h = sha.sha()
+          h.update(password)
+          h.update(binascii.unhexlify(challenge))
+          self._simple("user", user, h.hexdigest())
+        else:
+          self._simple("cookie", cookie)
         self.state = 'connected'
       except socket.error, e:
         self._disconnect()
         self.state = 'connected'
       except socket.error, e:
         self._disconnect()
@@ -393,16 +416,6 @@ class client:
   ########################################################################
   # Operations
 
   ########################################################################
   # Operations
 
-  def become(self, who):
-    """Become another user.
-
-    Arguments:
-    who -- the user to become.
-
-    Only trusted users can perform this operation.
-    """
-    self._simple("become", who)
-
   def play(self, track):
     """Play a track.
 
   def play(self, track):
     """Play a track.
 
@@ -478,7 +491,7 @@ class client:
 
   def version(self):
     """Return the server's version number."""
 
   def version(self):
     """Return the server's version number."""
-    return self._simple("version")[1]
+    return _split(self._simple("version")[1])[0]
 
   def playing(self):
     """Return the currently playing track.
 
   def playing(self):
     """Return the currently playing track.
@@ -609,7 +622,7 @@ class client:
     if ret == 555:
       return None
     else:
     if ret == 555:
       return None
     else:
-      return details
+      return _split(details)[0]
 
   def prefs(self, track):
     """Get all the preferences for a track.
 
   def prefs(self, track):
     """Get all the preferences for a track.
@@ -800,7 +813,7 @@ class client:
     The return value is the preference 
     """
     ret, details = self._simple("part", track, context, part)
     The return value is the preference 
     """
     ret, details = self._simple("part", track, context, part)
-    return details
+    return _split(details)[0]
 
   def setglobal(self, key, value):
     """Set a global preference value.
 
   def setglobal(self, key, value):
     """Set a global preference value.
@@ -831,7 +844,51 @@ class client:
     if ret == 555:
       return None
     else:
     if ret == 555:
       return None
     else:
-      return details
+      return _split(details)[0]
+
+  def make_cookie(self):
+    """Create a login cookie"""
+    ret, details = self._simple("make-cookie")
+    return _split(details)[0]
+  
+  def revoke(self):
+    """Revoke a login cookie"""
+    self._simple("revoke")
+
+  def adduser(self, user, password):
+    """Create a user"""
+    self._simple("adduser", user, password)
+
+  def deluser(self, user):
+    """Delete a user"""
+    self._simple("deluser", user)
+
+  def userinfo(self, user, key):
+    """Get user information"""
+    res, details = self._simple("userinfo", user, key)
+    if res == 555:
+      return None
+    return _split(details)[0]
+
+  def edituser(self, user, key, value):
+    """Set user information"""
+    self._simple("edituser", user, key, value)
+
+  def users(self):
+    """List all users
+
+    The return value is a list of all users."""
+    self._simple("users")
+    return self._body()
+
+  def register(self, username, password, email):
+    """Register a user"""
+    res, details = self._simple("register", username, password, email)
+    return _split(details)[0]
+
+  def confirm(self, confirmation):
+    """Confirm a user registration"""
+    res, details = self._simple("confirm", confirmation)
 
   ########################################################################
   # I/O infrastructure
 
   ########################################################################
   # I/O infrastructure