1 #import "JubCLIChatUI.h"
2 #import "JubChatClient.h"
3 #import "JubCLIColor.h"
4 #import "JubCLICommand.h"
7 BEGINCLICOMMAND(JubCLIReplyCommand, @":r", nil,
8 @"Sets the sender of the last incomming message as the default recipient")
10 if (_ui.lastIn == nil) {
11 [of_stdout writeLine: @"No message has been received yet"];
15 _ui.sink = (JubCLIChatUI*)[_ui.client chatForContact: _ui.lastIn];
16 [of_stdout writeFormat: @"Set sink to %@\n",
17 [_ui.lastIn.rosterItem.JID bareJID]];
21 BEGINCLICOMMAND(JubCLISetSinkCommand, @":s", @"<who>",
22 @"Selects <who> as the default recipient")
24 if ([parameters count] != 1) {
25 [of_stdout writeLine: @"Syntax: ':s <who>'"];
29 OFString *param = parameters[0];
30 XMPPContact *contact = _ui.client.contactManager.contacts[param];
33 [of_stdout writeFormat: @"Contact '%@' not found in your "
38 _ui.sink = (JubCLIChatUI*)[_ui.client chatForContact: contact];
40 [of_stdout writeFormat: @"Set sink to %@\n", param];
44 BEGINCLICOMMAND(JubCLIMessageCommand, @":m", @"<who> <message>",
45 @"Sends a single message to <who>")
47 if ([parameters count] < 2) {
48 [of_stdout writeLine: @"Syntax: ':m <who> <message>'"];
52 XMPPContact *contact =
53 _ui.client.contactManager.contacts[parameters[0]];
56 [of_stdout writeFormat: @"Contact %@ not found in your "
57 @"roster\n", parameters[0]];
62 (JubCLIChatUI*)[_ui.client chatForContact: contact];
65 [parameters arrayByRemovingObject: [parameters firstObject]];
67 [chat send: [message componentsJoinedByString: @" "]];
71 BEGINCLICOMMAND(JubCLIPresenceCommand, @":t", @"<status> [<message>]",
72 @"Changes your presence")
74 if ([parameters count] < 1) {
76 @"Syntax: ':t <status> [<message>]'"];
80 OFString *show = parameters[0];
82 if (![@[ @"available", @"away", @"dnd", @"xa", @"chat", @"unavailable" ]
83 containsObject: show]) {
84 [of_stdout writeLine: @"<status> must be one of: "
85 @"available, away, dnd, xa, chat, unavailable"];
89 if ([parameters count] == 2) {
90 [_ui.client sendPresenceWithStatus: show];
94 OFString *message = [[parameters
95 arrayByRemovingObject: [parameters firstObject]]
96 componentsJoinedByString: @" "];
98 [_ui.client sendPresenceWithStatus: show
103 BEGINCLICOMMAND(JubCLIRosterCommand, @":roster", nil, @"Shows your roster")
105 OFDictionary *contacts = _ui.client.contactManager.contacts;
106 for (OFString *key in contacts) {
107 XMPPContact *contact = contacts[key];
108 OFString *name = contact.rosterItem.name;
109 XMPPPresence *presence =
110 [[[contact.presences allObjects] sortedArray] firstObject];
113 [of_stdout writeFormat: @"%@ <%@> (", name, key];
115 [of_stdout writeFormat: @"%@ (", key];
118 [of_stdout writeFormat: COL_OFFLINE(@"offline")];
119 else if ([presence.show isEqual: @"chat"])
120 [of_stdout writeFormat: COL_CHAT(@"free for chat")];
121 else if ([presence.show isEqual: @"away"])
122 [of_stdout writeFormat: COL_AWAY(@"away")];
123 else if ([presence.show isEqual: @"xa"])
124 [of_stdout writeFormat: COL_XA(@"extended away")];
125 else if ([presence.show isEqual: @"dnd"])
126 [of_stdout writeFormat: COL_DND(@"do not disturb")];
128 [of_stdout writeFormat: COL_ONLINE(@"online")];
130 [of_stdout writeString: @")\n"];
135 @implementation JubCLIUI
136 @synthesize client = _client;
137 @synthesize lastIn = _lastIn;
138 @synthesize sink = _sink;
140 - initWithClient: (JubChatClient*)client
145 _commands = [OFMutableDictionary new];
146 _client = [client retain];
147 _contactManager = client.contactManager;
148 [_contactManager addDelegate: self];
150 [self addCommand: [[[JubCLIReplyCommand alloc]
151 initWithCLIUI: self] autorelease]];
153 [self addCommand: [[[JubCLISetSinkCommand alloc]
154 initWithCLIUI: self] autorelease]];
156 [self addCommand: [[[JubCLIMessageCommand alloc]
157 initWithCLIUI: self] autorelease]];
159 [self addCommand: [[[JubCLIPresenceCommand alloc]
160 initWithCLIUI: self] autorelease]];
162 [self addCommand: [[[JubCLIRosterCommand alloc]
163 initWithCLIUI: self] autorelease]];
174 [_contactManager removeDelegate: self];
180 - (void)startUIThread
182 [of_stdin asyncReadLineWithTarget: self
183 selector: @selector(Jub_userInputWithStream:
187 - (void)client: (JubChatClient*)client
188 didChangePresence: (XMPPPresence*)presence
194 return [JubCLIChatUI class];
197 - (void)addCommand: (id<JubCLICommand>)command
199 [_commands setObject: command
200 forKey: command.command];
203 - (BOOL)Jub_userInputWithStream: (OFStream*)stream
204 line: (OFString*)line
205 exception: (OFException*)exception
208 [OFApplication terminate];
210 if ([line length] == 0)
213 if ([line characterAtIndex: 0] != ':') {
215 [of_stdout writeLine: @"No default sink selected, "
216 @"type `:h` for help"];
223 line = [line stringByDeletingTrailingWhitespaces];
225 OFArray *input= [line componentsSeparatedByString: @" "];
227 if ([input[0] isEqual: @":h"]) {
228 __block size_t longest = 0;
230 [_commands enumerateKeysAndObjectsUsingBlock:
231 ^(OFString *key, id<JubCLICommand> command, bool *stop) {
232 size_t length = [command.command length] +
233 (command.params == nil ? 0 :
234 (1 + [command.params length]));
236 if (length > longest)
240 for (OFString *key in [[_commands allKeys] sortedArray]) {
241 id<JubCLICommand> command = _commands[key];
242 size_t length = [command.command length] +
243 (command.params == nil ? 0 :
244 (1 + [command.params length]));
246 if (command.params == nil)
247 [of_stdout writeFormat: @"`%@`",
250 [of_stdout writeFormat: @"`%@ %@`",
251 command.command, command.params];
253 // This is NOT distributive due to integer arithmetic
254 size_t padding = (longest + 2)/8 - (length + 2)/8;
256 for (size_t i = 0; i <= padding; i++)
257 [of_stdout writeString: @"\t"];
259 [of_stdout writeFormat: @"- %@\n", command.help];
265 id<JubCLICommand> command = _commands[input[0]];
268 [command callWithParameters:
269 [input arrayByRemovingObject: [input firstObject]]];
274 [of_stdout writeLine: @"Invalid command, type `:h` for help"];
279 - (void)contact: (XMPPContact*)contact
280 didSendMessage: (XMPPMessage*)message
282 if (message.body == nil || ![message.type isEqual: @"chat"])
288 - (void)contact: (XMPPContact*)contact
289 didSendPresence: (XMPPPresence*)presence
291 [of_stdout writeFormat: BOLD("%@") @" is now in state ", presence.from];
293 if ([presence.type isEqual: @"unavailable"])
294 [of_stdout writeFormat: COL_OFFLINE(@"offline")];
295 else if ([presence.show isEqual: @"chat"])
296 [of_stdout writeFormat: COL_CHAT(@"free for chat")];
297 else if ([presence.show isEqual: @"away"])
298 [of_stdout writeFormat: COL_AWAY(@"away")];
299 else if ([presence.show isEqual: @"xa"])
300 [of_stdout writeFormat: COL_XA(@"extended away")];
301 else if ([presence.show isEqual: @"dnd"])
302 [of_stdout writeFormat: COL_DND(@"do not disturb")];
304 [of_stdout writeFormat: COL_ONLINE(@"online")];
306 if (presence.status != nil)
307 [of_stdout writeFormat: @": %@", presence.status];
309 [of_stdout writeString: @"\n"];