]> cgit.babelmonkeys.de Git - jubjub.git/blob - src/gui/cli/JubCLIUI.m
Move presence changing to JubChatClient
[jubjub.git] / src / gui / cli / JubCLIUI.m
1 #import "JubCLIChatUI.h"
2 #import "JubChatClient.h"
3 #import "JubCLIColor.h"
4 #import "JubCLICommand.h"
5 #import "JubCLIUI.h"
6
7 BEGINCLICOMMAND(JubCLIReplyCommand, @":r", nil,
8     @"Sets the sender of the last incomming message as the default recipient")
9 {
10         if (_ui.lastIn == nil) {
11                 [of_stdout writeLine: @"No message has been received yet"];
12                 return;
13         }
14
15         _ui.sink = (JubCLIChatUI*)[_ui.client chatForContact: _ui.lastIn];
16         [of_stdout writeFormat: @"Set sink to %@\n",
17             [_ui.lastIn.rosterItem.JID bareJID]];
18 }
19 ENDCLICOMMAND
20
21 BEGINCLICOMMAND(JubCLISetSinkCommand, @":s", @"<who>",
22     @"Selects <who> as the default recipient")
23 {
24         if ([parameters count] != 1) {
25                 [of_stdout writeLine: @"Syntax: ':s <who>'"];
26                 return;
27         }
28
29         OFString *param = parameters[0];
30         XMPPContact *contact = _ui.client.contactManager.contacts[param];
31
32         if (contact == nil) {
33                 [of_stdout writeFormat: @"Contact '%@' not found in your "
34                     @"roster\n", param];
35                 return;
36         }
37
38         _ui.sink = (JubCLIChatUI*)[_ui.client chatForContact: contact];
39
40         [of_stdout writeFormat: @"Set sink to %@\n", param];
41 }
42 ENDCLICOMMAND
43
44 BEGINCLICOMMAND(JubCLIMessageCommand, @":m", @"<who> <message>",
45     @"Sends a single message to <who>")
46 {
47         if ([parameters count] < 2) {
48                 [of_stdout writeLine: @"Syntax: ':m <who> <message>'"];
49                 return;
50         }
51
52         XMPPContact *contact =
53             _ui.client.contactManager.contacts[parameters[0]];
54
55         if (contact == nil) {
56                 [of_stdout writeFormat: @"Contact %@ not found in your "
57                     @"roster\n", parameters[0]];
58                 return;
59         }
60
61         JubCLIChatUI *chat =
62             (JubCLIChatUI*)[_ui.client chatForContact: contact];
63
64         OFArray *message =
65             [parameters arrayByRemovingObject: [parameters firstObject]];
66
67         [chat send: [message componentsJoinedByString: @" "]];
68 }
69 ENDCLICOMMAND
70
71 BEGINCLICOMMAND(JubCLIPresenceCommand, @":t", @"<status> [<message>]",
72     @"Changes your presence")
73 {
74         if ([parameters count] < 1) {
75                 [of_stdout writeLine:
76                     @"Syntax: ':t <status> [<message>]'"];
77                 return;
78         }
79
80         OFString *show = parameters[0];
81
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"];
86                 return;
87         }
88
89         if ([parameters count] == 2) {
90                 [_ui.client sendPresenceWithStatus: show];
91                 return;
92         }
93
94         OFString *message = [[parameters
95             arrayByRemovingObject: [parameters firstObject]]
96                 componentsJoinedByString: @" "];
97
98         [_ui.client sendPresenceWithStatus: show
99                                       text: message];
100 }
101 ENDCLICOMMAND
102
103 BEGINCLICOMMAND(JubCLIRosterCommand, @":roster", nil, @"Shows your roster")
104 {
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];
111
112                 if (name != nil)
113                         [of_stdout writeFormat: @"%@ <%@> (", name, key];
114                 else
115                         [of_stdout writeFormat: @"%@ (", key];
116
117                 if (presence == nil)
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")];
127                 else
128                         [of_stdout writeFormat: COL_ONLINE(@"online")];
129
130                 [of_stdout writeString: @")\n"];
131         }
132 }
133 ENDCLICOMMAND
134
135 @implementation JubCLIUI
136 @synthesize client = _client;
137 @synthesize lastIn = _lastIn;
138 @synthesize sink = _sink;
139
140 - initWithClient: (JubChatClient*)client
141 {
142         self = [super init];
143
144         @try {
145                 _commands =  [OFMutableDictionary new];
146                 _client = [client retain];
147                 _contactManager = client.contactManager;
148                 [_contactManager addDelegate: self];
149
150                 [self addCommand: [[[JubCLIReplyCommand alloc]
151                                        initWithCLIUI: self] autorelease]];
152
153                 [self addCommand: [[[JubCLISetSinkCommand alloc]
154                                        initWithCLIUI: self] autorelease]];
155
156                 [self addCommand: [[[JubCLIMessageCommand alloc]
157                                        initWithCLIUI: self] autorelease]];
158
159                 [self addCommand: [[[JubCLIPresenceCommand alloc]
160                                        initWithCLIUI: self] autorelease]];
161
162                 [self addCommand: [[[JubCLIRosterCommand alloc]
163                                        initWithCLIUI: self] autorelease]];
164         } @catch (id e) {
165                 [self release];
166                 @throw e;
167         }
168
169         return self;
170 }
171
172 - (void)dealloc
173 {
174         [_contactManager removeDelegate: self];
175         [_client release];
176         [_commands release];
177         [super dealloc];
178 }
179
180 - (void)startUIThread
181 {
182         [of_stdin asyncReadLineWithTarget: self
183                                  selector: @selector(Jub_userInputWithStream:
184                                                      line:exception:)];
185 }
186
187 -      (void)client: (JubChatClient*)client
188   didChangePresence: (XMPPPresence*)presence
189 {
190 }
191
192 - (Class)chatUIClass
193 {
194         return [JubCLIChatUI class];
195 }
196
197 - (void)addCommand: (id<JubCLICommand>)command
198 {
199         [_commands setObject: command
200                       forKey: command.command];
201 }
202
203 - (BOOL)Jub_userInputWithStream: (OFStream*)stream
204                            line: (OFString*)line
205                       exception: (OFException*)exception
206 {
207         if (line == nil)
208                 [OFApplication terminate];
209
210         if ([line length] == 0)
211                 return YES;
212
213         if ([line characterAtIndex: 0] != ':') {
214                 if (_sink == nil)
215                         [of_stdout writeLine: @"No default sink selected, "
216                             @"type `:h` for help"];
217
218                 [_sink send: line];
219
220                 return YES;
221         }
222
223         line = [line stringByDeletingTrailingWhitespaces];
224
225         OFArray *input= [line componentsSeparatedByString: @" "];
226
227         if ([input[0] isEqual: @":h"]) {
228                 __block size_t longest = 0;
229
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]));
235
236                         if (length > longest)
237                                 longest = length;
238                 }];
239
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]));
245
246                         if (command.params == nil)
247                                 [of_stdout writeFormat: @"`%@`",
248                                     command.command];
249                         else
250                                 [of_stdout writeFormat: @"`%@ %@`",
251                                     command.command, command.params];
252
253                         // This is NOT distributive due to integer arithmetic
254                         size_t padding = (longest + 2)/8 - (length + 2)/8;
255
256                         for (size_t i = 0; i <= padding; i++)
257                                 [of_stdout writeString: @"\t"];
258
259                         [of_stdout writeFormat: @"- %@\n", command.help];
260                 };
261
262                 return YES;
263         }
264
265         id<JubCLICommand> command = _commands[input[0]];
266
267         if (command) {
268                 [command callWithParameters:
269                     [input arrayByRemovingObject: [input firstObject]]];
270
271                 return YES;
272         }
273
274         [of_stdout writeLine: @"Invalid command, type `:h` for help"];
275
276         return YES;
277 }
278
279 -  (void)contact: (XMPPContact*)contact
280   didSendMessage: (XMPPMessage*)message
281 {
282         if (message.body == nil || ![message.type isEqual: @"chat"])
283                 return;
284
285         _lastIn =  contact;
286 }
287
288 -   (void)contact: (XMPPContact*)contact
289   didSendPresence: (XMPPPresence*)presence
290 {
291         [of_stdout writeFormat: BOLD("%@") @" is now in state ", presence.from];
292
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")];
303         else
304                 [of_stdout writeFormat: COL_ONLINE(@"online")];
305
306         if (presence.status != nil)
307                 [of_stdout writeFormat: @": %@", presence.status];
308
309         [of_stdout writeString: @"\n"];
310 }
311 @end