Commit | Line | Data |
---|---|---|
92f3b0d7 FT |
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 | ||
fbe30a6d | 18 | from dolmod import * |
c5de778c | 19 | import os |
fbe30a6d | 20 | |
21 | def login(useauthless = True, **kw): | |
ff076c0a | 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 | """ | |
fbe30a6d | 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 | ||
9cbeb60c | 45 | def mustconnect(host, revision = latest): |
ff076c0a | 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 | """ | |
9cbeb60c | 53 | fd = connect(host) |
fbe30a6d | 54 | while True: |
55 | resp = getresp() | |
56 | if resp is not None and resp.getcmd() == u".connect": | |
57 | break | |
58 | select() | |
9cbeb60c | 59 | if resp.getcode() != 201: |
fbe30a6d | 60 | raise RuntimeError, resp.intresp()[0][0] |
9cbeb60c | 61 | if not checkproto(resp, revision): |
62 | raise RuntimeError, resp | |
00ea2039 | 63 | return fd |
fbe30a6d | 64 | |
9cbeb60c | 65 | def cnl(host = None, useauthless = True, revision = latest, **kw): |
ff076c0a | 66 | """A convenience function for connect and loginasync. |
67 | ||
68 | This function will connect to the given server, or the server in | |
17537706 | 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. | |
ff076c0a | 72 | """ |
c5de778c | 73 | if host is None: |
74 | host = os.getenv("DCSERVER") | |
75 | if host is None: | |
17537706 | 76 | host = "localhost" |
9cbeb60c | 77 | fd = mustconnect(host, revision) |
fbe30a6d | 78 | err, reason = login(useauthless, **kw) |
79 | if err != "success": | |
80 | raise RuntimeError, (err, reason) | |
00ea2039 | 81 | return fd |
fbe30a6d | 82 | |
83 | def ecmd(*args): | |
ff076c0a | 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 | """ | |
fbe30a6d | 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): | |
ff076c0a | 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 | """ | |
fbe30a6d | 106 | resp = ecmd(*args) |
107 | if resp.getcode() != code: | |
108 | raise ValueError, resp.getcode() | |
109 | return resp | |
194d48ea | 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: | |
f04b2c3c | 119 | raise ValueError, tuple(resp.extract()[0]) |
194d48ea | 120 | return resp |
54b4a861 | 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 |