5ee9e40301c99ee953f5e8feff167bbe313ad2a8
[doldaconnect.git] / lib / python / dolcon / __init__.py
1 #  Dolda Connect - Modular multiuser Direct Connect-style client
2 #  Copyright (C) 2007 Fredrik Tolf <fredrik@dolda2000.com>
3 #  
4 #  This program is free software; you can redistribute it and/or modify
5 #  it under the terms of the GNU General Public License as published by
6 #  the Free Software Foundation; either version 2 of the License, or
7 #  (at your option) any later version.
8 #  
9 #  This program is distributed in the hope that it will be useful,
10 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
11 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 #  GNU General Public License for more details.
13 #  
14 #  You should have received a copy of the GNU General Public License
15 #  along with this program; if not, write to the Free Software
16 #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17
18 from dolmod import *
19 import os
20
21 def login(useauthless = True, **kw):
22     """A convenience function for loginasync.
23
24     This function will initiate an asynchronous login per the
25     loginasync command, and then run a select loop while waiting for
26     it to complete. It will return a tuple (res, reason), where res is
27     the result code, and reason is an explanatory text for any error.
28
29     res can be any of the following:
30      * success:  Login completed successfully
31      * nologin:  No authentication mechanism could be negotiated
32      * server:   An error occurred on the server
33      * user:     An error occurred in the library
34      * conv:     The password conversation mechanism failed
35      * authfail: The server refused the login (due to e.g. bad credentials)
36     """
37     result = [None]
38     def mycb(*v):
39         result[0] = v
40     loginasync(mycb, useauthless, **kw)
41     while result[0] is None:
42         select()
43     return result[0]
44
45 def mustconnect(host, revision = latest):
46     """A convenience function for connect.
47
48     This function will connect to the given host, perform a select
49     loop, and ensure that the server approves of the connection. If
50     any of these steps fail, an exception is raised. If successful,
51     the file descriptor for the server connection is returned.
52     """
53     fd = connect(host)
54     while True:
55         resp = getresp()
56         if resp is not None and resp.getcmd() == u".connect":
57             break
58         select()
59     if resp.getcode() != 201:
60         raise RuntimeError, resp.intresp()[0][0]
61     if not checkproto(resp, revision):
62         raise RuntimeError, resp
63     return fd
64
65 def cnl(host = None, useauthless = True, revision = latest, **kw):
66     """A convenience function for connect and loginasync.
67
68     This function will connect to the given server, or the server in
69     the environment variable $DCSERVER if none is given, or, if that
70     fails, localhost, and authenticate to the server. If any of the
71     steps fail, an exception is raised.
72     """
73     if host is None:
74         host = os.getenv("DCSERVER")
75     if host is None:
76         host = "localhost"
77     fd = mustconnect(host, revision)
78     err, reason = login(useauthless, **kw)
79     if err != "success":
80         raise RuntimeError, (err, reason)
81     return fd
82     
83 def ecmd(*args):
84     """A convenience function for qcmd.
85
86     This function will queue the given command, and then wait in a
87     select loop until the command has been carried out. The return
88     value is a Response object, corresponding to the reponse from the
89     server.
90     """
91     tag = qcmd(*args)
92     while True:
93         resp = getresp(tag)
94         if resp is not None:
95             break;
96         select()
97     return resp
98
99 def ecmda(code, *args):
100     """A convenience function for ecmd.
101
102     This function does essentially the same as ecmd, but it will also
103     check so that the response has the given numerical code. If not,
104     an exception is raised.
105     """
106     resp = ecmd(*args)
107     if resp.getcode() != code:
108         raise ValueError, resp.getcode()
109     return resp
110
111 def ecmds(*args):
112     """Another convenience function for ecmd.
113
114     Like ecmda, but will fail on all 5xx codes, and succeed on all
115     others.
116     """
117     resp = ecmd(*args)
118     if resp.getcode() >= 500 and resp.getcode() < 600:
119         raise ValueError, tuple(resp.extract()[0])
120     return resp
121
122 def getresps():
123     """A generator function which will iterate over all responses from
124     getresp.
125     """
126     while True:
127         resp = getresp()
128         if resp is None:
129             break
130         else:
131             yield resp