2 Copyright (C) 2000-2004 SKYRIX Software AG
4 This file is part of OpenGroupware.org.
6 OGo is free software; you can redistribute it and/or modify it under
7 the terms of the GNU Lesser General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 OGo is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with OGo; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
25 A neat tool to call XML-RPC servers from the shell.
30 forceauth - bool - send the credentials in the first request!
33 #include <NGXmlRpc/NGXmlRpcClient.h>
35 #include <NGExtensions/NSString+Ext.h>
36 #include <NGStreams/NGStreams.h>
37 #include <NGStreams/NGNet.h>
39 #if !LIB_FOUNDATION_LIBRARY
40 # include <NGObjWeb/UnixSignalHandler.h>
47 @interface NGXmlRpcClient(CallFailed)
48 - (id)callFailed:(WOResponse *)_response;
49 @end /* NGXmlRpcClient */
51 @class HandleCredentialsClient;
53 @interface XmlRpcClient : NSObject
55 HandleCredentialsClient *client;
62 - (id)initWithArguments:(NSArray *)_arguments;
63 - (void)initMethodCall:(NSArray *)_arguments;
64 - (BOOL)initXmlRpcClientWithStringURL:(NSString *)_url;
67 - (void)help:(NSString *)pn;
69 - (void)printElement:(id)_element;
70 - (void)printDictionary:(NSDictionary *)_dict;
71 - (void)printArray:(NSArray *)_array;
73 @end /* XmlRpcClient */
75 @implementation NSObject(Printing)
77 - (void)printWithTool:(XmlRpcClient *)_tool {
78 printf("%s\n", [[self description] cString]);
81 @end /* NSObject(Printing) */
83 @implementation NSData(Printing)
85 - (void)printWithTool:(XmlRpcClient *)_tool {
86 fwrite([self bytes], [self length], 1, stdout);
89 @end /* NSData(Printing) */
91 @implementation NSDictionary(Printing)
93 - (void)printWithTool:(XmlRpcClient *)_tool {
94 [_tool printDictionary:self];
97 @end /* NSDictionary(Printing) */
99 @implementation NSArray(Printing)
101 - (void)printWithTool:(XmlRpcClient *)_tool {
102 [_tool printArray:self];
105 @end /* NSArray(Printing) */
107 @implementation NSException(Printing)
109 - (void)printWithTool:(XmlRpcClient *)_tool {
110 printf("Exception caught\nName : %s\nReason: %s\n",
111 [[self name] cString], [[self reason] cString]);
114 @end /* NSException(Printing) */
116 @interface HandleCredentialsClient : NGXmlRpcClient
119 NSString *defPassword;
124 - (void)setDefLogin:(NSString *)_login;
125 - (void)setDefPassword:(NSString *)_pwd;
127 @end /* HandleCredentialsClient */
130 #include <NGObjWeb/WOResponse.h>
132 @implementation HandleCredentialsClient
135 [self->defLogin release];
136 [self->defPassword release];
142 - (void)setDefLogin:(NSString *)_login {
143 ASSIGNCOPY(self->defLogin, _login);
145 - (void)setDefPassword:(NSString *)_pwd {
146 ASSIGNCOPY(self->defPassword, _pwd);
151 - (NSString *)prompt:(NSString *)_prompt {
155 fprintf(stderr, "%s", [_prompt cString]);
157 fgets(clogin, 200, stdin);
158 clogin[strlen(clogin) - 1] = '\0';
159 login = [NSString stringWithCString:clogin];
163 - (NSString *)promptPassword:(NSString *)_prompt {
167 cpwd = getpass("password: ");
168 pwd = [NSString stringWithCString:cpwd];
172 - (id)callFailed:(WOResponse *)_response {
173 if ([_response status] == 401) {
178 wwwauth = [_response headerForKey:@"www-authenticate"];
179 if ([[wwwauth lowercaseString] hasPrefix:@"digest"])
180 [self logWithFormat:@"Digest authentication:\n'%@'", wwwauth];
182 // TODO: test credentials of URL
184 if (self->defLogin) {
185 user = [self->defLogin autorelease];
186 self->defLogin = nil;
189 user = [self prompt:@"login: "];
191 if (self->defPassword) {
192 pass = [self->defPassword autorelease];
193 self->defPassword = nil;
196 pass = [self promptPassword:@"password: "];
198 [self setUserName:user];
199 [self setPassword:pass];
201 /* this "should" return some kind of "need-pwd" object ... */
205 return [super callFailed:_response];
209 @end /* HandleCredentialsClient */
213 @implementation XmlRpcClient
218 return [self initWithArguments:nil];
221 - (id)initWithArguments:(NSArray *)_arguments {
222 if ((self = [super init])) {
227 argc = [_arguments count];
229 [self help:[_arguments objectAtIndex:0]];
233 s = [_arguments objectAtIndex:1];
234 if (![self initXmlRpcClientWithStringURL:s]) {
235 printf("Error initializing the XML-RPC client\n");
241 [self initMethodCall:_arguments];
244 self->methodName = @"system.listMethods";
245 self->parameters = nil;
248 ud = [NSUserDefaults standardUserDefaults];
249 if ([ud boolForKey:@"forceauth"]) {
250 [self->client setUserName:[ud stringForKey:@"login"]];
251 [self->client setPassword:[ud stringForKey:@"password"]];
254 [self->client setDefLogin:[ud stringForKey:@"login"]];
255 [self->client setDefPassword:[ud stringForKey:@"password"]];
261 - (BOOL)initXmlRpcClientWithStringURL:(NSString *)_url {
264 if (![_url isAbsoluteURL]) {
265 /* make a raw, Unix domain socket connection */
266 NGLocalSocketAddress *addr;
268 addr = [NGLocalSocketAddress addressWithPath:_url];
269 self->client = [[HandleCredentialsClient alloc] initWithRawAddress:addr];
273 if ((url = [NSURL URLWithString:_url]) != nil) {
275 if ((uri = [url path]) == nil)
279 self->client = [[HandleCredentialsClient alloc] initWithURL:url];
284 printf("Invalid URL\n");
289 - (void)initMethodCall:(NSArray *)_arguments {
290 self->methodName = [_arguments objectAtIndex:2];
292 if ([_arguments count] > 2) {
293 NSRange range = NSMakeRange(3, [_arguments count] - 3);
294 self->parameters = [[_arguments subarrayWithRange:range] retain];
299 [self->client release];
300 [self->methodName release];
301 [self->parameters release];
307 - (void)printElement:(id)element {
308 [element printWithTool:self];
311 /* printing objects */
313 - (void)printDictionary:(NSDictionary *)_dict {
314 NSEnumerator *dictEnum;
317 dictEnum = [_dict keyEnumerator];
319 while((dictKey = [dictEnum nextObject])) {
320 printf("%s=", [dictKey cString]);
321 [self printElement:[_dict objectForKey:dictKey]];
325 - (void)printArray:(NSArray *)_array {
326 NSEnumerator *arrayEnum;
329 arrayEnum = [_array objectEnumerator];
330 while((arrayElem = [arrayEnum nextObject])) {
331 [self printElement:arrayElem];
335 - (void)help:(NSString *)pn {
337 "usage: %s <url> [<method-name>] [<arg1>,...]\n"
338 " sample: %s http://localhost:20000/RPC2 bc 1 2\n",
339 [pn cString], [pn cString]);
347 if (self->client == nil) {
348 NSLog(@"missing XML-RPC client object ...");
353 result = [self->client
354 invokeMethodNamed:self->methodName
355 parameters:self->parameters];
358 while ((result == nil) && loopCount < 20);
361 NSLog(@"call failed, no result (looped %i times) ?!", loopCount);
365 [self printElement:result];
367 if ([result isKindOfClass:[NSException class]]) {
374 @end /* XmlRpcClient */
376 int main(int argc, char **argv, char **env) {
377 NSAutoreleasePool *pool;
378 XmlRpcClient *client;
382 pool = [[NSAutoreleasePool alloc] init];
383 #if LIB_FOUNDATION_LIBRARY || defined(GS_PASS_ARGUMENTS)
384 [NSProcessInfo initializeWithArguments:argv count:argc environment:env];
387 /* our sockets need to know, if the PIPE is broken */
388 signal(SIGPIPE, SIG_IGN);
390 arguments = [[NSProcessInfo processInfo] argumentsWithoutDefaults];
391 if ((client = [[XmlRpcClient alloc] initWithArguments:arguments]) == nil)
394 exitCode = [client run];