Mercurial > pidgin
annotate src/protocols/msn/cmdproc.c @ 10451:92d4a25fd33c
[gaim-migrate @ 11717]
This is patch 1090620 from Felipe Contreras to improve the handling of the
Individuals group on MSN and better buddy updates (modified by me to work in
HEAD)
Also included is my fix for bug 1090087 "MSN Groupchat Double Invite Crash",
a few spelling corrections, and make some more strings translatable.
committer: Tailor Script <tailor@pidgin.im>
author | Stu Tomlinson <stu@nosnilmot.com> |
---|---|
date | Thu, 30 Dec 2004 15:55:19 +0000 |
parents | e5455f1dc9b6 |
children | bcfea6c3d5c9 |
rev | line source |
---|---|
8810 | 1 /** |
2 * @file cmdproc.c MSN command processor functions | |
3 * | |
4 * gaim | |
5 * | |
9198
ab6636c5a136
[gaim-migrate @ 9993]
Christian Hammond <chipx86@chipx86.com>
parents:
9193
diff
changeset
|
6 * Gaim is the legal property of its developers, whose names are too numerous |
ab6636c5a136
[gaim-migrate @ 9993]
Christian Hammond <chipx86@chipx86.com>
parents:
9193
diff
changeset
|
7 * to list here. Please refer to the COPYRIGHT file distributed with this |
ab6636c5a136
[gaim-migrate @ 9993]
Christian Hammond <chipx86@chipx86.com>
parents:
9193
diff
changeset
|
8 * source distribution. |
8810 | 9 * |
10 * This program is free software; you can redistribute it and/or modify | |
11 * it under the terms of the GNU General Public License as published by | |
12 * the Free Software Foundation; either version 2 of the License, or | |
13 * (at your option) any later version. | |
14 * | |
15 * This program is distributed in the hope that it will be useful, | |
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 * GNU General Public License for more details. | |
19 * | |
20 * You should have received a copy of the GNU General Public License | |
21 * along with this program; if not, write to the Free Software | |
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
23 */ | |
24 #include "msn.h" | |
25 #include "cmdproc.h" | |
26 | |
27 MsnCmdProc * | |
28 msn_cmdproc_new(MsnSession *session) | |
29 { | |
30 MsnCmdProc *cmdproc; | |
31 | |
32 cmdproc = g_new0(MsnCmdProc, 1); | |
33 | |
34 cmdproc->session = session; | |
35 cmdproc->txqueue = g_queue_new(); | |
36 cmdproc->history = msn_history_new(); | |
37 | |
38 return cmdproc; | |
39 } | |
40 | |
41 void | |
42 msn_cmdproc_destroy(MsnCmdProc *cmdproc) | |
43 { | |
44 MsnTransaction *trans; | |
45 | |
46 if (cmdproc->last_trans != NULL) | |
47 g_free(cmdproc->last_trans); | |
48 | |
49 while ((trans = g_queue_pop_head(cmdproc->txqueue)) != NULL) | |
50 msn_transaction_destroy(trans); | |
51 | |
52 g_queue_free(cmdproc->txqueue); | |
53 | |
54 msn_history_destroy(cmdproc->history); | |
55 } | |
56 | |
57 void | |
58 msn_cmdproc_process_queue(MsnCmdProc *cmdproc) | |
59 { | |
60 MsnTransaction *trans; | |
61 | |
62 while ((trans = g_queue_pop_head(cmdproc->txqueue)) != NULL && | |
63 cmdproc->error == 0) | |
64 { | |
65 msn_cmdproc_send_trans(cmdproc, trans); | |
66 } | |
67 } | |
68 | |
69 void | |
70 msn_cmdproc_queue_trans(MsnCmdProc *cmdproc, MsnTransaction *trans) | |
71 { | |
72 g_return_if_fail(cmdproc != NULL); | |
73 g_return_if_fail(trans != NULL); | |
74 | |
75 g_queue_push_tail(cmdproc->txqueue, trans); | |
76 } | |
77 | |
78 static void | |
79 show_debug_cmd(MsnCmdProc *cmdproc, gboolean incoming, const char *command) | |
80 { | |
81 MsnServConn *servconn; | |
82 const char *names[] = { "NS", "SB" }; | |
83 char *show; | |
84 char tmp; | |
85 size_t len; | |
86 | |
87 servconn = cmdproc->servconn; | |
88 len = strlen(command); | |
89 show = g_strdup(command); | |
90 | |
91 tmp = (incoming) ? 'S' : 'C'; | |
92 | |
93 if ((show[len - 1] == '\n') && (show[len - 2] == '\r')) | |
94 { | |
95 show[len - 2] = '\0'; | |
96 } | |
97 | |
98 gaim_debug_misc("msn", "%c: %s %03d: %s\n", tmp, | |
99 names[servconn->type], servconn->num, show); | |
100 | |
101 g_free(show); | |
102 } | |
103 | |
104 void | |
105 msn_cmdproc_send_trans(MsnCmdProc *cmdproc, MsnTransaction *trans) | |
106 { | |
107 MsnServConn *servconn; | |
108 char *data; | |
9193
502707ca1836
[gaim-migrate @ 9988]
Christian Hammond <chipx86@chipx86.com>
parents:
9158
diff
changeset
|
109 size_t len; |
8810 | 110 |
111 g_return_if_fail(cmdproc != NULL); | |
10403 | 112 g_return_if_fail(cmdproc->ready); |
8810 | 113 g_return_if_fail(trans != NULL); |
114 | |
115 servconn = cmdproc->servconn; | |
116 msn_history_add(cmdproc->history, trans); | |
117 | |
118 data = msn_transaction_to_string(trans); | |
9158
c30d81b4dd22
[gaim-migrate @ 9942]
Christian Hammond <chipx86@chipx86.com>
parents:
8830
diff
changeset
|
119 |
10284 | 120 if (cmdproc->last_trans != NULL) |
121 g_free(cmdproc->last_trans); | |
122 | |
8810 | 123 cmdproc->last_trans = g_strdup(data); |
124 | |
125 len = strlen(data); | |
126 | |
127 show_debug_cmd(cmdproc, FALSE, data); | |
128 | |
129 if (trans->callbacks == NULL) | |
130 trans->callbacks = g_hash_table_lookup(cmdproc->cbs_table->cmds, | |
131 trans->command); | |
132 | |
133 if (trans->payload != NULL) | |
134 { | |
135 data = g_realloc(data, len + trans->payload_len); | |
136 memcpy(data + len, trans->payload, trans->payload_len); | |
137 len += trans->payload_len; | |
138 } | |
139 | |
140 msn_servconn_write(servconn, data, len); | |
141 | |
142 g_free(data); | |
143 } | |
144 | |
145 void | |
146 msn_cmdproc_send_quick(MsnCmdProc *cmdproc, const char *command, | |
147 const char *format, ...) | |
148 { | |
149 MsnServConn *servconn; | |
150 char *data; | |
8830
f8038b1f7449
[gaim-migrate @ 9594]
Christian Hammond <chipx86@chipx86.com>
parents:
8810
diff
changeset
|
151 char *params = NULL; |
8810 | 152 va_list arg; |
153 size_t len; | |
154 | |
155 g_return_if_fail(cmdproc != NULL); | |
10403 | 156 g_return_if_fail(cmdproc->ready); |
8810 | 157 g_return_if_fail(command != NULL); |
158 | |
159 servconn = cmdproc->servconn; | |
160 | |
9158
c30d81b4dd22
[gaim-migrate @ 9942]
Christian Hammond <chipx86@chipx86.com>
parents:
8830
diff
changeset
|
161 if (format != NULL) |
c30d81b4dd22
[gaim-migrate @ 9942]
Christian Hammond <chipx86@chipx86.com>
parents:
8830
diff
changeset
|
162 { |
8830
f8038b1f7449
[gaim-migrate @ 9594]
Christian Hammond <chipx86@chipx86.com>
parents:
8810
diff
changeset
|
163 va_start(arg, format); |
f8038b1f7449
[gaim-migrate @ 9594]
Christian Hammond <chipx86@chipx86.com>
parents:
8810
diff
changeset
|
164 params = g_strdup_vprintf(format, arg); |
f8038b1f7449
[gaim-migrate @ 9594]
Christian Hammond <chipx86@chipx86.com>
parents:
8810
diff
changeset
|
165 va_end(arg); |
f8038b1f7449
[gaim-migrate @ 9594]
Christian Hammond <chipx86@chipx86.com>
parents:
8810
diff
changeset
|
166 } |
8810 | 167 |
168 if (params != NULL) | |
169 data = g_strdup_printf("%s %s\r\n", command, params); | |
170 else | |
171 data = g_strdup_printf("%s\r\n", command); | |
172 | |
173 g_free(params); | |
174 | |
175 len = strlen(data); | |
176 | |
177 show_debug_cmd(cmdproc, FALSE, data); | |
178 | |
179 msn_servconn_write(servconn, data, len); | |
180 | |
181 g_free(data); | |
182 } | |
183 | |
184 void | |
185 msn_cmdproc_send(MsnCmdProc *cmdproc, const char *command, | |
186 const char *format, ...) | |
187 { | |
188 MsnTransaction *trans; | |
189 va_list arg; | |
190 | |
191 g_return_if_fail(cmdproc != NULL); | |
10403 | 192 g_return_if_fail(cmdproc->ready); |
8810 | 193 g_return_if_fail(command != NULL); |
194 | |
195 trans = g_new0(MsnTransaction, 1); | |
196 | |
197 trans->command = g_strdup(command); | |
198 | |
9158
c30d81b4dd22
[gaim-migrate @ 9942]
Christian Hammond <chipx86@chipx86.com>
parents:
8830
diff
changeset
|
199 if (format != NULL) |
c30d81b4dd22
[gaim-migrate @ 9942]
Christian Hammond <chipx86@chipx86.com>
parents:
8830
diff
changeset
|
200 { |
8830
f8038b1f7449
[gaim-migrate @ 9594]
Christian Hammond <chipx86@chipx86.com>
parents:
8810
diff
changeset
|
201 va_start(arg, format); |
f8038b1f7449
[gaim-migrate @ 9594]
Christian Hammond <chipx86@chipx86.com>
parents:
8810
diff
changeset
|
202 trans->params = g_strdup_vprintf(format, arg); |
f8038b1f7449
[gaim-migrate @ 9594]
Christian Hammond <chipx86@chipx86.com>
parents:
8810
diff
changeset
|
203 va_end(arg); |
f8038b1f7449
[gaim-migrate @ 9594]
Christian Hammond <chipx86@chipx86.com>
parents:
8810
diff
changeset
|
204 } |
8810 | 205 |
206 msn_cmdproc_send_trans(cmdproc, trans); | |
207 } | |
208 | |
209 void | |
9158
c30d81b4dd22
[gaim-migrate @ 9942]
Christian Hammond <chipx86@chipx86.com>
parents:
8830
diff
changeset
|
210 msn_cmdproc_process_payload(MsnCmdProc *cmdproc, char *payload, |
c30d81b4dd22
[gaim-migrate @ 9942]
Christian Hammond <chipx86@chipx86.com>
parents:
8830
diff
changeset
|
211 int payload_len) |
c30d81b4dd22
[gaim-migrate @ 9942]
Christian Hammond <chipx86@chipx86.com>
parents:
8830
diff
changeset
|
212 { |
9193
502707ca1836
[gaim-migrate @ 9988]
Christian Hammond <chipx86@chipx86.com>
parents:
9158
diff
changeset
|
213 MsnCommand *last; |
502707ca1836
[gaim-migrate @ 9988]
Christian Hammond <chipx86@chipx86.com>
parents:
9158
diff
changeset
|
214 |
502707ca1836
[gaim-migrate @ 9988]
Christian Hammond <chipx86@chipx86.com>
parents:
9158
diff
changeset
|
215 g_return_if_fail(cmdproc != NULL); |
9158
c30d81b4dd22
[gaim-migrate @ 9942]
Christian Hammond <chipx86@chipx86.com>
parents:
8830
diff
changeset
|
216 |
9193
502707ca1836
[gaim-migrate @ 9988]
Christian Hammond <chipx86@chipx86.com>
parents:
9158
diff
changeset
|
217 last = cmdproc->last_cmd; |
502707ca1836
[gaim-migrate @ 9988]
Christian Hammond <chipx86@chipx86.com>
parents:
9158
diff
changeset
|
218 last->payload = g_memdup(payload, payload_len); |
502707ca1836
[gaim-migrate @ 9988]
Christian Hammond <chipx86@chipx86.com>
parents:
9158
diff
changeset
|
219 last->payload_len = payload_len; |
502707ca1836
[gaim-migrate @ 9988]
Christian Hammond <chipx86@chipx86.com>
parents:
9158
diff
changeset
|
220 |
502707ca1836
[gaim-migrate @ 9988]
Christian Hammond <chipx86@chipx86.com>
parents:
9158
diff
changeset
|
221 if (last->payload_cb != NULL) |
502707ca1836
[gaim-migrate @ 9988]
Christian Hammond <chipx86@chipx86.com>
parents:
9158
diff
changeset
|
222 last->payload_cb(cmdproc, last, payload, payload_len); |
9158
c30d81b4dd22
[gaim-migrate @ 9942]
Christian Hammond <chipx86@chipx86.com>
parents:
8830
diff
changeset
|
223 } |
c30d81b4dd22
[gaim-migrate @ 9942]
Christian Hammond <chipx86@chipx86.com>
parents:
8830
diff
changeset
|
224 |
c30d81b4dd22
[gaim-migrate @ 9942]
Christian Hammond <chipx86@chipx86.com>
parents:
8830
diff
changeset
|
225 void |
8810 | 226 msn_cmdproc_process_msg(MsnCmdProc *cmdproc, MsnMessage *msg) |
227 { | |
10345 | 228 MsnMsgTypeCb cb; |
8810 | 229 |
9881 | 230 if (msn_message_get_content_type(msg) == NULL) |
231 { | |
232 gaim_debug_misc("msn", "failed to find message content\n"); | |
233 return; | |
234 } | |
235 | |
8810 | 236 cb = g_hash_table_lookup(cmdproc->cbs_table->msgs, |
237 msn_message_get_content_type(msg)); | |
238 | |
239 if (cb == NULL) | |
240 { | |
9158
c30d81b4dd22
[gaim-migrate @ 9942]
Christian Hammond <chipx86@chipx86.com>
parents:
8830
diff
changeset
|
241 gaim_debug_warning("msn", "Unhandled content-type '%s'\n", |
c30d81b4dd22
[gaim-migrate @ 9942]
Christian Hammond <chipx86@chipx86.com>
parents:
8830
diff
changeset
|
242 msn_message_get_content_type(msg)); |
8810 | 243 |
244 return; | |
245 } | |
246 | |
247 cb(cmdproc, msg); | |
248 } | |
249 | |
250 void | |
251 msn_cmdproc_process_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) | |
252 { | |
9193
502707ca1836
[gaim-migrate @ 9988]
Christian Hammond <chipx86@chipx86.com>
parents:
9158
diff
changeset
|
253 MsnTransCb cb = NULL; |
8810 | 254 MsnTransaction *trans = NULL; |
255 | |
256 if (cmd->trId) | |
257 trans = msn_history_find(cmdproc->history, cmd->trId); | |
258 | |
10225 | 259 if (trans != NULL) |
260 if (trans->timer) | |
261 gaim_timeout_remove(trans->timer); | |
262 | |
8810 | 263 if (g_ascii_isdigit(cmd->command[0])) |
264 { | |
265 if (trans != NULL) | |
266 { | |
267 MsnErrorCb error_cb = NULL; | |
268 int error; | |
269 | |
270 error = atoi(cmd->command); | |
10225 | 271 |
272 if (trans->error_cb != NULL) | |
273 error_cb = trans->error_cb; | |
274 | |
275 if (error_cb == NULL && cmdproc->cbs_table->errors != NULL) | |
8810 | 276 error_cb = g_hash_table_lookup(cmdproc->cbs_table->errors, trans->command); |
277 | |
278 if (error_cb != NULL) | |
10225 | 279 { |
8810 | 280 error_cb(cmdproc, trans, error); |
10225 | 281 } |
8810 | 282 else |
283 { | |
284 #if 1 | |
285 msn_error_handle(cmdproc->session, error); | |
286 #else | |
287 gaim_debug_warning("msn", "Unhandled error '%s'\n", | |
288 cmd->command); | |
289 #endif | |
290 } | |
291 | |
292 return; | |
293 } | |
294 } | |
295 | |
296 if (cmdproc->cbs_table->async != NULL) | |
297 cb = g_hash_table_lookup(cmdproc->cbs_table->async, cmd->command); | |
298 | |
9193
502707ca1836
[gaim-migrate @ 9988]
Christian Hammond <chipx86@chipx86.com>
parents:
9158
diff
changeset
|
299 if (cb == NULL && trans != NULL) |
8810 | 300 { |
9193
502707ca1836
[gaim-migrate @ 9988]
Christian Hammond <chipx86@chipx86.com>
parents:
9158
diff
changeset
|
301 cmd->trans = trans; |
8810 | 302 |
9193
502707ca1836
[gaim-migrate @ 9988]
Christian Hammond <chipx86@chipx86.com>
parents:
9158
diff
changeset
|
303 if (trans->callbacks != NULL) |
502707ca1836
[gaim-migrate @ 9988]
Christian Hammond <chipx86@chipx86.com>
parents:
9158
diff
changeset
|
304 cb = g_hash_table_lookup(trans->callbacks, cmd->command); |
8810 | 305 } |
306 | |
10043 | 307 if (cb == NULL && cmdproc->cbs_table->fallback != NULL) |
308 cb = g_hash_table_lookup(cmdproc->cbs_table->fallback, cmd->command); | |
309 | |
8810 | 310 if (cb != NULL) |
9193
502707ca1836
[gaim-migrate @ 9988]
Christian Hammond <chipx86@chipx86.com>
parents:
9158
diff
changeset
|
311 { |
8810 | 312 cb(cmdproc, cmd); |
9193
502707ca1836
[gaim-migrate @ 9988]
Christian Hammond <chipx86@chipx86.com>
parents:
9158
diff
changeset
|
313 } |
8810 | 314 else |
315 { | |
316 gaim_debug_warning("msn", "Unhandled command '%s'\n", | |
9158
c30d81b4dd22
[gaim-migrate @ 9942]
Christian Hammond <chipx86@chipx86.com>
parents:
8830
diff
changeset
|
317 cmd->command); |
8810 | 318 } |
319 | |
9193
502707ca1836
[gaim-migrate @ 9988]
Christian Hammond <chipx86@chipx86.com>
parents:
9158
diff
changeset
|
320 #if 1 |
502707ca1836
[gaim-migrate @ 9988]
Christian Hammond <chipx86@chipx86.com>
parents:
9158
diff
changeset
|
321 /* TODO this is really ugly */ |
502707ca1836
[gaim-migrate @ 9988]
Christian Hammond <chipx86@chipx86.com>
parents:
9158
diff
changeset
|
322 /* Since commands have not stored payload and we need it for pendent |
502707ca1836
[gaim-migrate @ 9988]
Christian Hammond <chipx86@chipx86.com>
parents:
9158
diff
changeset
|
323 * commands at the time we process again the same command we will try |
502707ca1836
[gaim-migrate @ 9988]
Christian Hammond <chipx86@chipx86.com>
parents:
9158
diff
changeset
|
324 * to read again the payload of payload_len size but we will actually |
10310 | 325 * read sometime else, and reading from server synchronization goes to |
9193
502707ca1836
[gaim-migrate @ 9988]
Christian Hammond <chipx86@chipx86.com>
parents:
9158
diff
changeset
|
326 * hell. */ |
502707ca1836
[gaim-migrate @ 9988]
Christian Hammond <chipx86@chipx86.com>
parents:
9158
diff
changeset
|
327 /* Now we store the payload in the command when we queue them :D */ |
8810 | 328 |
9193
502707ca1836
[gaim-migrate @ 9988]
Christian Hammond <chipx86@chipx86.com>
parents:
9158
diff
changeset
|
329 if (trans != NULL && trans->pendent_cmd != NULL) |
502707ca1836
[gaim-migrate @ 9988]
Christian Hammond <chipx86@chipx86.com>
parents:
9158
diff
changeset
|
330 if (cmdproc->ready) |
502707ca1836
[gaim-migrate @ 9988]
Christian Hammond <chipx86@chipx86.com>
parents:
9158
diff
changeset
|
331 msn_transaction_unqueue_cmd(trans, cmdproc); |
502707ca1836
[gaim-migrate @ 9988]
Christian Hammond <chipx86@chipx86.com>
parents:
9158
diff
changeset
|
332 #endif |
8810 | 333 } |
334 | |
335 void | |
336 msn_cmdproc_process_cmd_text(MsnCmdProc *cmdproc, const char *command) | |
337 { | |
338 show_debug_cmd(cmdproc, TRUE, command); | |
339 | |
340 if (cmdproc->last_cmd != NULL) | |
341 msn_command_destroy(cmdproc->last_cmd); | |
342 | |
343 cmdproc->last_cmd = msn_command_from_string(command); | |
344 | |
345 msn_cmdproc_process_cmd(cmdproc, cmdproc->last_cmd); | |
346 } | |
347 | |
348 void | |
9193
502707ca1836
[gaim-migrate @ 9988]
Christian Hammond <chipx86@chipx86.com>
parents:
9158
diff
changeset
|
349 msn_cmdproc_show_error(MsnCmdProc *cmdproc, int error) |
8810 | 350 { |
9193
502707ca1836
[gaim-migrate @ 9988]
Christian Hammond <chipx86@chipx86.com>
parents:
9158
diff
changeset
|
351 GaimConnection *gc = |
502707ca1836
[gaim-migrate @ 9988]
Christian Hammond <chipx86@chipx86.com>
parents:
9158
diff
changeset
|
352 gaim_account_get_connection(cmdproc->session->account); |
8810 | 353 |
9193
502707ca1836
[gaim-migrate @ 9988]
Christian Hammond <chipx86@chipx86.com>
parents:
9158
diff
changeset
|
354 char *tmp; |
8810 | 355 |
9193
502707ca1836
[gaim-migrate @ 9988]
Christian Hammond <chipx86@chipx86.com>
parents:
9158
diff
changeset
|
356 tmp = NULL; |
8810 | 357 |
9193
502707ca1836
[gaim-migrate @ 9988]
Christian Hammond <chipx86@chipx86.com>
parents:
9158
diff
changeset
|
358 switch (error) |
8810 | 359 { |
9193
502707ca1836
[gaim-migrate @ 9988]
Christian Hammond <chipx86@chipx86.com>
parents:
9158
diff
changeset
|
360 case MSN_ERROR_MISC: |
502707ca1836
[gaim-migrate @ 9988]
Christian Hammond <chipx86@chipx86.com>
parents:
9158
diff
changeset
|
361 tmp = _("Miscellaneous error"); break; |
502707ca1836
[gaim-migrate @ 9988]
Christian Hammond <chipx86@chipx86.com>
parents:
9158
diff
changeset
|
362 case MSN_ERROR_SIGNOTHER: |
9641 | 363 gc->wants_to_die = TRUE; |
9193
502707ca1836
[gaim-migrate @ 9988]
Christian Hammond <chipx86@chipx86.com>
parents:
9158
diff
changeset
|
364 tmp = _("You have signed on from another location."); break; |
502707ca1836
[gaim-migrate @ 9988]
Christian Hammond <chipx86@chipx86.com>
parents:
9158
diff
changeset
|
365 case MSN_ERROR_SERVDOWN: |
502707ca1836
[gaim-migrate @ 9988]
Christian Hammond <chipx86@chipx86.com>
parents:
9158
diff
changeset
|
366 tmp = _("The MSN servers are going down temporarily."); break; |
502707ca1836
[gaim-migrate @ 9988]
Christian Hammond <chipx86@chipx86.com>
parents:
9158
diff
changeset
|
367 default: |
8810 | 368 break; |
369 } | |
370 | |
9193
502707ca1836
[gaim-migrate @ 9988]
Christian Hammond <chipx86@chipx86.com>
parents:
9158
diff
changeset
|
371 if (tmp != NULL) |
502707ca1836
[gaim-migrate @ 9988]
Christian Hammond <chipx86@chipx86.com>
parents:
9158
diff
changeset
|
372 { |
502707ca1836
[gaim-migrate @ 9988]
Christian Hammond <chipx86@chipx86.com>
parents:
9158
diff
changeset
|
373 gaim_connection_error(gc, tmp); |
502707ca1836
[gaim-migrate @ 9988]
Christian Hammond <chipx86@chipx86.com>
parents:
9158
diff
changeset
|
374 } |
8810 | 375 } |