Merge commit 'upstream/0.7.1' into debian
Laurent Bigonville
13 years ago
0 | Mikhail Zabaluev <first.surname@nokia.com> | |
0 | Mikhail Zabaluev <mikhail.zabaluev@nokia.com> | |
1 | 1 | Kai Vehmanen <first.surname@nokia.com> |
2 | 2 | Martti Mela <first.surname@nokia.com> |
3 | 3 | Simon McVittie <simon.mcvittie@collabora.co.uk> |
4 | 4 | Rob Taylor <rob.taylor@collabora.co.uk> |
5 | 5 | Senko Rasic <senko.rasic@collabora.co.uk> |
6 | Jonny Lamb <jonny.lamb@collabora.co.uk> | |
7 | David Laban <david.laban@collabora.co.uk> | |
6 | 8 | |
7 | 9 | Authors for original telepathy-gabble code: |
8 | 10 | Robert McQueen <robert.mcqueen@collabora.co.uk> |
0 | commit b3d95a10e75eece58379c93308a88f58560a769e | |
1 | Author: Mikhail Zabaluev <mikhail.zabaluev@nokia.com> | |
2 | Date: 2011-02-01 21:15:06 +0200 | |
3 | ||
4 | Version 0.7.1 | |
5 | ||
6 | commit 0ec7a23893b4c85a359f6349578ed34cf5e595ea | |
7 | Author: Mikhail Zabaluev <mikhail.zabaluev@nokia.com> | |
8 | Date: 2011-02-01 21:34:26 +0200 | |
9 | ||
10 | voip_test is not a test script, move it to EXTRA_DIST | |
11 | ||
12 | commit 1f51b77c6df5e5af0bd6aca31927e842a4d86b72 | |
13 | Author: Mikhail Zabaluev <mikhail.zabaluev@nokia.com> | |
14 | Date: 2011-02-01 21:28:35 +0200 | |
15 | ||
16 | Added voip_test to dist files | |
17 | ||
18 | commit 95e060c7696c93d92b151651cff758015b5a9405 | |
19 | Author: Mikhail Zabaluev <mikhail.zabaluev@nokia.com> | |
20 | Date: 2011-02-01 21:14:07 +0200 | |
21 | ||
22 | Added Jonny Lamb and David Laban to the list of authors | |
23 | ||
24 | commit e4006c401c93e57b337249fd8c2891bff32dc894 | |
25 | Author: David Laban <david.laban@collabora.co.uk> | |
26 | Date: 2011-01-31 18:47:01 +0000 | |
27 | ||
28 | Add test for fd.o:33716 | |
29 | ||
30 | commit b47726b065fb5e054bc2ab096755c989d294a3c1 | |
31 | Author: David Laban <david.laban@collabora.co.uk> | |
32 | Date: 2011-01-31 19:08:19 +0000 | |
33 | ||
34 | remove references to twisted.words.xish | |
35 | ||
36 | commit e0b4d040e816d1918913bdebcdc156351a679476 | |
37 | Author: David Laban <david.laban@collabora.co.uk> | |
38 | Date: 2011-01-31 19:00:38 +0000 | |
39 | ||
40 | Revert "Check for Python module twisted.words.xish as required for unit tests" | |
41 | ||
42 | This reverts commit dfb7be1f4d652d48ac001f9e496abd97006c1ba3. | |
43 | ||
44 | Sorry. That was sloppy of me. I don't actually use xpath. | |
45 | ||
46 | commit dfb7be1f4d652d48ac001f9e496abd97006c1ba3 | |
47 | Author: Mikhail Zabaluev <mikhail.zabaluev@nokia.com> | |
48 | Date: 2011-01-31 20:46:33 +0200 | |
49 | ||
50 | Check for Python module twisted.words.xish as required for unit tests | |
51 | ||
52 | commit df7937078faa3211a8eaae0342cd7bf297b4fc20 | |
53 | Merge: 776194c f69dc4b | |
54 | Author: Mikhail Zabaluev <mikhail.zabaluev@nokia.com> | |
55 | Date: 2011-01-31 20:37:37 +0200 | |
56 | ||
57 | Merge branch 'invite-from-self' | |
58 | ||
59 | commit 776194c93cc447aede374f011dff5b1d49b2b0ed | |
60 | Merge: abcfb59 2cf3c1e | |
61 | Author: David Laban <david.laban@collabora.co.uk> | |
62 | Date: 2011-01-31 18:23:54 +0000 | |
63 | ||
64 | Merge remote branch 'alsuren/streamedmedia_tests' | |
65 | ||
66 | Reviewed-by: Will Thompson <will.thompson@collabora.co.uk> | |
67 | ||
68 | commit f69dc4be0e713eef64ecb65c84ded2fa357b39b9 | |
69 | Author: Mikhail Zabaluev <mikhail.zabaluev@nokia.com> | |
70 | Date: 2011-01-31 19:46:47 +0200 | |
71 | ||
72 | Reject incoming calls from the same URI as the local user (fd.o #33716) | |
73 | ||
74 | This is not supported in StreamedMedia channels, and an assertion | |
75 | in tpsip_media_channel_receive_invite() sees to it. | |
76 | ||
77 | commit c4cffddbaea180ba3fddebed81097c03e2cca959 | |
78 | Author: Mikhail Zabaluev <mikhail.zabaluev@nokia.com> | |
79 | Date: 2011-01-29 13:45:31 +0200 | |
80 | ||
81 | Nano version 0.6.5.1 | |
82 | ||
83 | commit a6c7d52dac100d5f9ea97c68e7197f6d41756435 | |
84 | Author: Mikhail Zabaluev <mikhail.zabaluev@nokia.com> | |
85 | Date: 2011-01-29 00:40:32 +0200 | |
86 | ||
87 | Version 0.6.5 | |
88 | ||
89 | commit abcfb59b2ae9613585515fd887f026591ffe77fd | |
90 | Merge: 9eb2013 68b99ed | |
91 | Author: Mikhail Zabaluev <mikhail.zabaluev@nokia.com> | |
92 | Date: 2011-01-28 21:18:51 +0200 | |
93 | ||
94 | Merge branch 'signed-param-fix' | |
95 | ||
96 | commit 68b99ed09a29fa567d0a49789389ba8b545d0226 | |
97 | Author: Mikhail Zabaluev <mikhail.zabaluev@nokia.com> | |
98 | Date: 2011-01-28 20:36:42 +0200 | |
99 | ||
100 | Changed the size parameter type to signed in tpsip_unquote_string() | |
101 | ||
102 | The special value of -1 implies that the type should be signed. | |
103 | ||
104 | commit caf244b6d1b38cc42291ce0697374fae6f5a4148 | |
105 | Merge: 8932d71 09dd7ac | |
106 | Author: Mikhail Zabaluev <mikhail.zabaluev@nokia.com> | |
107 | Date: 2011-01-28 20:54:36 +0200 | |
108 | ||
109 | Backported fixes to fd.o #31720 onto telepathy-sofiasip-0.6 | |
110 | ||
111 | commit 09dd7ac499d83eb40154c6415a77fa89cfaac880 | |
112 | Author: Simon McVittie <simon.mcvittie@collabora.co.uk> | |
113 | Date: 2010-11-18 13:46:18 +0000 | |
114 | ||
115 | fd.o #31720: use TpDBusDaemon to export media streams | |
116 | ||
117 | commit 91e347eaf9e1a75b81943286c7308164663c9010 | |
118 | Author: Simon McVittie <simon.mcvittie@collabora.co.uk> | |
119 | Date: 2010-11-18 13:46:06 +0000 | |
120 | ||
121 | fd.o #31720: use TpDBusDaemon to export media sessions | |
122 | ||
123 | commit 9486db40a0f0836b65d46ea925216126c6fe2709 | |
124 | Author: Simon McVittie <simon.mcvittie@collabora.co.uk> | |
125 | Date: 2010-11-18 13:45:40 +0000 | |
126 | ||
127 | Backported fix to fd.o #31720: use TpDBusDaemon to export channel objects | |
128 | ||
129 | Backported to telepathy-sofiasip-0.6 | |
130 | ||
131 | commit 2cf3c1e745c27dd48d71b05e5daa68479333885b | |
132 | Author: David Laban <david.laban@collabora.co.uk> | |
133 | Date: 2011-01-26 17:12:09 +0000 | |
134 | ||
135 | Fix group flags for streamedmedia calls. | |
136 | ||
137 | We start off with lots of flags, and then delete them as we work out what | |
138 | kind of channel we are, rather than trying to track what we need to | |
139 | add/remove over time. We should always have the right flags before we are | |
140 | advertised on the bus. | |
141 | ||
142 | Note that adding members to a channel made using Create isn't *strictly* | |
143 | correct way to do it, but it isn't special-cased in any of the code, and | |
144 | I don't want to set flags that are lies so I've just updated the tests | |
145 | accordingly. | |
146 | ||
147 | Also, converting the flags to their binary representation makes failed | |
148 | assertions a lot easier to debug (and I honestly don't care about speed). | |
149 | ||
150 | commit c10bee3f1c4f02f1ca758999ef420c21a4996443 | |
151 | Author: David Laban <david.laban@collabora.co.uk> | |
152 | Date: 2011-01-26 15:35:03 +0000 | |
153 | ||
154 | sip-media-channel clean up group members | |
155 | ||
156 | Use tp_intset_new_containing() wherever it's sensible | |
157 | This makes sets with only one member simpler and less think-o prone. | |
158 | (We still use tp_intset_new() for groups with more than one member) | |
159 | ||
160 | Use better variable names for clarity. | |
161 | (We still use "set" in priv_session_state_changed_cb() to avoid too much | |
162 | code churn) | |
163 | ||
164 | commit 630113129f088d29aa4be60bcfbe66a3cd564a55 | |
165 | Author: David Laban <david.laban@collabora.co.uk> | |
166 | Date: 2011-01-26 14:20:17 +0000 | |
167 | ||
168 | voip tests: BYE message needs a reply. Add to tests. | |
169 | ||
170 | commit e5bf266a20d817a22c70efc31fc5d34913c1f3df | |
171 | Author: David Laban <david.laban@collabora.co.uk> | |
172 | Date: 2011-01-26 14:09:47 +0000 | |
173 | ||
174 | Fix review comments for tests. | |
175 | ||
176 | commit c40b48866b7bd04308b26725368304c555cc69fd | |
177 | Author: David Laban <david.laban@collabora.co.uk> | |
178 | Date: 2010-12-07 19:53:37 +0000 | |
179 | ||
180 | add new tests to make check | |
181 | ||
182 | commit 3683f1b456ef9baa2fefc885fe1e458b769647bf | |
183 | Author: David Laban <david.laban@collabora.co.uk> | |
184 | Date: 2010-12-07 18:39:31 +0000 | |
185 | ||
186 | Fix up incoming-basics.py | |
187 | ||
188 | * Same deal as outgoing-basics, but in one commit. | |
189 | * Also, expect the NewChannels signal rather than NewChannel. | |
190 | * Add context.send_message() and implement .incoming_call(), .ack() and | |
191 | .terminate() based on it. | |
192 | * FIXME #32189: group flags are borked. | |
193 | ||
194 | commit 8f241d940ecfcc366ce3dedb5b077d73d379965c | |
195 | Author: David Laban <david.laban@collabora.co.uk> | |
196 | Date: 2010-12-07 18:09:33 +0000 | |
197 | ||
198 | Complete outgoing-basics.py | |
199 | ||
200 | sofiatest.py: | |
201 | * add sip headers to Events for convenience | |
202 | ||
203 | voip_test.py:VoipTestContext: | |
204 | * add {get, check}_call_sdp() | |
205 | * add accept() (secretly also records call-id) | |
206 | ||
207 | outgoing_basics.py: | |
208 | * Call NativeCandidatesPrepared() because RAWUDP requires it. | |
209 | * Expect sip-* events rather than stream-iq ones. | |
210 | ||
211 | commit 744205d25b59848c56902a4fdfd7134d575f8794 | |
212 | Author: David Laban <david.laban@collabora.co.uk> | |
213 | Date: 2010-12-07 17:45:57 +0000 | |
214 | ||
215 | Update the groups interface when remote user accepts the call. | |
216 | ||
217 | commit 76cba776cacd54b3994a590e572b1a51c2217761 | |
218 | Author: David Laban <david.laban@collabora.co.uk> | |
219 | Date: 2010-12-06 18:49:40 +0000 | |
220 | ||
221 | import incoming-basics from gabble | |
222 | ||
223 | commit 364ff37b08cc76841312b04450cb8de9541f2ada | |
224 | Author: David Laban <david.laban@collabora.co.uk> | |
225 | Date: 2010-12-06 16:59:29 +0000 | |
226 | ||
227 | Don't call priv_outbound_call (self, 0) | |
228 | ||
229 | This previously happened if the client requested an anonymous | |
230 | streamedmedia channel, but doing so would cause a crash. | |
231 | ||
232 | commit 1de34ce405c9df7ea0953604ebfa19fc04b92f9d | |
233 | Author: David Laban <david.laban@collabora.co.uk> | |
234 | Date: 2010-12-07 19:46:53 +0000 | |
235 | ||
236 | Make outgoing-basics test work up until the first network traffic event. | |
237 | ||
238 | * Change from gabbletest to sofiatest, and import bits of gabble's | |
239 | jingletest2.py as voip_test.py | |
240 | * Get rid of JingleProtocol args to tests | |
241 | * Change variable names s/stream/sip_proxy/ and s/jt2/context/ | |
242 | * Change jids to sip uris. | |
243 | * Don't restrict ordering of NewStreamHandler signal emission, when | |
244 | all sane StreamEngine implementations do state recovery anyway. | |
245 | * Early-return before we expect any network traffic | |
246 | * Channel.Type.Call is not a requestable type. | |
247 | * change test_all_dialects back to exec_test calls. | |
248 | ||
249 | Things I'm not sure about: | |
250 | * FIXME: 32189: group flags are borked. | |
251 | * Are sofiasip's pending send flags correct? | |
252 | ||
253 | commit 85b5c6a95151c73fbd8a62fd541cadbbc81bf32a | |
254 | Author: David Laban <david.laban@collabora.co.uk> | |
255 | Date: 2010-12-03 18:54:36 +0000 | |
256 | ||
257 | implement tpsip_media_channel_get_handle() properly. | |
258 | ||
259 | commit a9f18ec9ffe748c2078886cbc51c28babc3ce944 | |
260 | Author: David Laban <david.laban@collabora.co.uk> | |
261 | Date: 2010-12-03 16:38:38 +0000 | |
262 | ||
263 | initial import of outgoing-basics.py from gabble | |
264 | ||
265 | commit 63dc72f4e45d249dc7cbccf9e721dc3ec07e2dc1 | |
266 | Author: David Laban <david.laban@collabora.co.uk> | |
267 | Date: 2010-12-07 19:34:56 +0000 | |
268 | ||
269 | Hacks to allow running multiple tests per process | |
270 | ||
271 | * Pick a random port to create the server on each run (since | |
272 | IListeningPort.stopListening() isn't guaranteed to have freed the port | |
273 | by the time it returns) | |
274 | * Don't install the colourer more than once | |
275 | * Fix the colourer to deal with "took $seconds" misc. | |
276 | ||
277 | We should probably try to consolidate these hacks with whatever gabbletest | |
278 | does, or maybe try to push more stuff into servicetest to make it easier | |
279 | to maintain, but let's wait until sofiasip has more tests before we start | |
280 | doing that. | |
281 | ||
282 | commit 9eb2013202cc29017c1925bd0e1d7c1906bf209b | |
283 | Author: Mikhail Zabaluev <mikhail.zabaluev@nokia.com> | |
284 | Date: 2011-01-03 18:26:27 +0200 | |
285 | ||
286 | Added a NEWS item for the upcoming release with warning about legacy loggers | |
287 | ||
288 | commit 79ff96db9d46dfe0c94442b954cf8b5c67b7df0b | |
289 | Author: Mikhail Zabaluev <mikhail.zabaluev@nokia.com> | |
290 | Date: 2011-01-03 17:56:45 +0200 | |
291 | ||
292 | Test the message-sent timestamp header with a fixed value | |
293 | ||
294 | commit 248b7a0c9b0efac2653c3e2659cbec1eda01d238 | |
295 | Merge: c89168e 6ef183a | |
296 | Author: Mikhail Zabaluev <mikhail.zabaluev@nokia.com> | |
297 | Date: 2011-01-03 17:45:15 +0200 | |
298 | ||
299 | Merge branch 'master' into messages-retouch | |
300 | ||
301 | commit 6ef183a45800b000fe1c402255e822963f90dc0c | |
302 | Author: Jonny Lamb <jonny.lamb@collabora.co.uk> | |
303 | Date: 2010-12-15 14:42:50 +0000 | |
304 | ||
305 | configure: increase version of tp-glib required | |
306 | ||
307 | This is required for TpBaseProtocolClass->dup_authentication_types. | |
308 | ||
309 | Signed-off-by: Jonny Lamb <jonny.lamb@collabora.co.uk> | |
310 | ||
311 | commit 96c98cfc3a7f59d0c04573098e498503b4ae4a47 | |
312 | Author: Jonny Lamb <jonny.lamb@collabora.co.uk> | |
313 | Date: 2010-12-15 14:38:27 +0000 | |
314 | ||
315 | protocol: implement TpBaseProtocolClass->dup_authentication_types | |
316 | ||
317 | Signed-off-by: Jonny Lamb <jonny.lamb@collabora.co.uk> | |
318 | ||
319 | commit fd3166fc69faa317c2d7d9f9770c6471d57e5a8d | |
320 | Author: David Laban <david.laban@collabora.co.uk> | |
321 | Date: 2010-12-13 20:34:52 +0000 | |
322 | ||
323 | test registering without a password | |
324 | ||
325 | and using a sasl channel to request the password if the server challenges, | |
326 | or not asking for a password if the server doesn't challenge. | |
327 | ||
328 | commit d2a65899f22ea3d91d7c47793298c55082668be1 | |
329 | Author: David Laban <david.laban@collabora.co.uk> | |
330 | Date: 2010-12-13 17:33:56 +0000 | |
331 | ||
332 | Don't ask the user for a password on connect | |
333 | ||
334 | We don't need to do this until the server asks us to authenticate. | |
335 | ||
336 | commit 75a2d3a792b54c328b809e1f260ad1e49632fb6e | |
337 | Author: David Laban <david.laban@collabora.co.uk> | |
338 | Date: 2010-12-13 17:13:01 +0000 | |
339 | ||
340 | Ask for a password in priv_handle_auth() if not given. | |
341 | ||
342 | This requires a call to tp_simple_password_manager_prompt_async(), so | |
343 | we create a data struct to help us split the function in half. | |
344 | ||
345 | Also, we move all checks from the second half of the function into the | |
346 | first, so they can be handled synchronously. | |
347 | ||
348 | The diff is clearer if you use git diff --patience. | |
349 | ||
350 | commit ef71b9dd869a46476fff2a49b942eb04d9928832 | |
351 | Author: Jonny Lamb <jonny.lamb@collabora.co.uk> | |
352 | Date: 2010-12-07 16:52:04 +0000 | |
353 | ||
354 | configure: depend on new enough tp-glib for TpSimplePasswordManager | |
355 | ||
356 | Signed-off-by: Jonny Lamb <jonny.lamb@collabora.co.uk> | |
357 | ||
358 | commit 04540e3ae94b618270bd3bb43b9ca6d75bf06ab8 | |
359 | Author: Jonny Lamb <jonny.lamb@collabora.co.uk> | |
360 | Date: 2010-12-07 16:43:34 +0000 | |
361 | ||
362 | connection: only disconnect if we're not already disconnected | |
363 | ||
364 | If we don't check this, tp-glib will give us a nice big fat warning. | |
365 | ||
366 | Signed-off-by: Jonny Lamb <jonny.lamb@collabora.co.uk> | |
367 | ||
368 | commit 9b24bd79a3f9437ea406ef4c412ff5aae84da2ce | |
369 | Author: Jonny Lamb <jonny.lamb@collabora.co.uk> | |
370 | Date: 2010-11-25 11:52:31 +0000 | |
371 | ||
372 | connection: use disconnect_with_dbus_error | |
373 | ||
374 | Signed-off-by: Jonny Lamb <jonny.lamb@collabora.co.uk> | |
375 | ||
376 | commit 7fd45d95dc7909585976670a77243a175d977734 | |
377 | Author: Jonny Lamb <jonny.lamb@collabora.co.uk> | |
378 | Date: 2010-11-24 16:26:08 +0000 | |
379 | ||
380 | connection: use TpSimplePasswordManager to get a password if one was not given | |
381 | ||
382 | Signed-off-by: Jonny Lamb <jonny.lamb@collabora.co.uk> | |
383 | ||
384 | commit d8e180b6f802cccea36fee81714d82203cba1f5b | |
385 | Author: Jonny Lamb <jonny.lamb@collabora.co.uk> | |
386 | Date: 2010-11-24 16:06:04 +0000 | |
387 | ||
388 | protocol: when hitting a special parameter, just skip it, not all the others too | |
389 | ||
390 | Signed-off-by: Jonny Lamb <jonny.lamb@collabora.co.uk> | |
391 | Reviewed-by: Simon McVittie <simon.mcvittie@collabora.co.uk> | |
392 | ||
393 | commit 825053fad9ac2b08ef47bb21a1dc29b0ca7be77f | |
394 | Author: Mikhail Zabaluev <mikhail.zabaluev@nokia.com> | |
395 | Date: 2010-11-23 19:31:28 +0200 | |
396 | ||
397 | Version 0.7.0.1 for development | |
398 | ||
0 | 399 | commit 15349832aea5b9c4a673e65f4099c116b24522e6 |
1 | 400 | Author: Mikhail Zabaluev <mikhail.zabaluev@nokia.com> |
2 | 401 | Date: 2010-11-23 18:54:20 +0200 |
118 | 517 | |
119 | 518 | fd.o #31720: use TpDBusDaemon to export channel objects |
120 | 519 | |
520 | commit c89168ecb97280c6e1f732c659c800af832bd7ab | |
521 | Author: Mikhail Zabaluev <mikhail.zabaluev@nokia.com> | |
522 | Date: 2010-11-03 17:39:58 +0200 | |
523 | ||
524 | Function call whitespace | |
525 | ||
526 | commit eaafc38c7f7252ea8d5792c14cd2499a6b9e1269 | |
527 | Author: Mikhail Zabaluev <mikhail.zabaluev@nokia.com> | |
528 | Date: 2010-11-03 17:39:34 +0200 | |
529 | ||
530 | Fix header value types for timestamps | |
531 | ||
532 | commit 4ae2883e410af411acc0d1c9096e3e11137cba81 | |
533 | Author: Mikhail Zabaluev <mikhail.zabaluev@nokia.com> | |
534 | Date: 2010-11-03 16:54:03 +0200 | |
535 | ||
536 | Test message headers "message-sent" and "message-received" | |
537 | ||
538 | commit 2c4c217d0b8320b86101200b80be35c03654d6f7 | |
539 | Author: Mikhail Zabaluev <mikhail.zabaluev@nokia.com> | |
540 | Date: 2010-11-03 16:53:44 +0200 | |
541 | ||
542 | Test "message-token" | |
543 | ||
544 | commit 90c49625330dd1f2dfa0c075271490fa1cad9518 | |
545 | Author: Mikhail Zabaluev <mikhail.zabaluev@nokia.com> | |
546 | Date: 2010-11-03 16:49:35 +0200 | |
547 | ||
548 | Add the header "message-sent" to received messages in Chan.I.Messages | |
549 | ||
550 | As retrieved from the Date header. | |
551 | ||
552 | commit 6b3085a3e3f0a310dc0625d8fd0e5b62241efd10 | |
553 | Author: Mikhail Zabaluev <mikhail.zabaluev@nokia.com> | |
554 | Date: 2010-11-03 16:47:58 +0200 | |
555 | ||
556 | Offer the header "message-token" on received messages in chan.I.Messages | |
557 | ||
121 | 558 | commit 1c9931a882038ac20ab45fe6de015cb8b76a841b |
122 | 559 | Author: Guillaume Desmottes <guillaume.desmottes@collabora.co.uk> |
123 | 560 | Date: 2010-10-27 16:33:46 +0200 |
149 | 586 | Date: 2010-10-27 10:14:21 +0200 |
150 | 587 | |
151 | 588 | depends on tp-glib 0.12.0 |
589 | ||
590 | commit 8932d71d3ead32065bd070a87b3cee811f6892ed | |
591 | Author: Mikhail Zabaluev <mikhail.zabaluev@nokia.com> | |
592 | Date: 2010-08-27 20:36:08 +0300 | |
593 | ||
594 | Nano version 0.6.4.1 | |
595 | ||
596 | commit 9cfa07f7dbabcf4faeff3e447aa743c118d4a012 | |
597 | Author: Mikhail Zabaluev <mikhail.zabaluev@nokia.com> | |
598 | Date: 2010-08-27 20:24:06 +0300 | |
599 | ||
600 | Version 0.6.4 | |
152 | 601 | |
153 | 602 | commit b80fdcb30fb9f37eeb042beade15e862f5d0b14c |
154 | 603 | Merge: 1cc6e02 fa3ba5a |
5 | 5 | recent at the top). |
6 | 6 | |
7 | 7 | See also ChangeLog. |
8 | ||
9 | telepathy-sofiasip 0.7.1 (2011-02-01) | |
10 | ------------------------------------- | |
11 | ||
12 | The "cross country" release. | |
13 | ||
14 | New features: | |
15 | ||
16 | - Added 'message-token' and 'message-sent' headers to incoming messages, | |
17 | derived from SIP message headers (fd.o #32607). | |
18 | NOTE: some existing clients logging messages, notably the one released | |
19 | in Maemo 5, make unrealistically strict assumptions about the uniqueness of | |
20 | 'message-token' values. These logging implementations may exhibit problems | |
21 | with handling collisions in token values if used with this or later versions | |
22 | of Telpathy-SofiaSIP. Such collisions are unlikely, but possible if a | |
23 | remote endpoint generating the SIP Call-ID headers does not use an algorithm | |
24 | compliant with the SIP specification to provide sufficient uniqueness. | |
25 | - Authentication channels implemented as a simple password challenge. | |
26 | ||
27 | Bugfixes: | |
28 | ||
29 | - Reject incoming calls from the same URI as the local user, rather than | |
30 | crashing apologetically (fd.o #33716). | |
31 | ||
32 | Other enhancements: | |
33 | ||
34 | - Test suite pulled up to Gabble standards. | |
35 | - Tests for basic StreamedMedia call cases (fd.o #32085) | |
36 | - Changed the type of the size parameter to gssize in tpsip_unquote_string(). | |
37 | ||
38 | Dependencies: | |
39 | ||
40 | - telepathy-glib >= 0.13.9 | |
8 | 41 | |
9 | 42 | telepathy-sofiasip 0.7.0 (2010-11-23) |
10 | 43 | ------------------------------------- |
0 | 0 | #! /bin/sh |
1 | 1 | # Guess values for system-dependent variables and create Makefiles. |
2 | # Generated by GNU Autoconf 2.67 for telepathy-sofiasip 0.7.0. | |
2 | # Generated by GNU Autoconf 2.67 for telepathy-sofiasip 0.7.1. | |
3 | 3 | # |
4 | 4 | # |
5 | 5 | # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, |
697 | 697 | # Identity of this package. |
698 | 698 | PACKAGE_NAME='telepathy-sofiasip' |
699 | 699 | PACKAGE_TARNAME='telepathy-sofiasip' |
700 | PACKAGE_VERSION='0.7.0' | |
701 | PACKAGE_STRING='telepathy-sofiasip 0.7.0' | |
700 | PACKAGE_VERSION='0.7.1' | |
701 | PACKAGE_STRING='telepathy-sofiasip 0.7.1' | |
702 | 702 | PACKAGE_BUGREPORT='' |
703 | 703 | PACKAGE_URL='' |
704 | 704 | |
1479 | 1479 | # Omit some internal or obsolete options to make the list less imposing. |
1480 | 1480 | # This message is too long to be a string in the A/UX 3.1 sh. |
1481 | 1481 | cat <<_ACEOF |
1482 | \`configure' configures telepathy-sofiasip 0.7.0 to adapt to many kinds of systems. | |
1482 | \`configure' configures telepathy-sofiasip 0.7.1 to adapt to many kinds of systems. | |
1483 | 1483 | |
1484 | 1484 | Usage: $0 [OPTION]... [VAR=VALUE]... |
1485 | 1485 | |
1550 | 1550 | |
1551 | 1551 | if test -n "$ac_init_help"; then |
1552 | 1552 | case $ac_init_help in |
1553 | short | recursive ) echo "Configuration of telepathy-sofiasip 0.7.0:";; | |
1553 | short | recursive ) echo "Configuration of telepathy-sofiasip 0.7.1:";; | |
1554 | 1554 | esac |
1555 | 1555 | cat <<\_ACEOF |
1556 | 1556 | |
1678 | 1678 | test -n "$ac_init_help" && exit $ac_status |
1679 | 1679 | if $ac_init_version; then |
1680 | 1680 | cat <<\_ACEOF |
1681 | telepathy-sofiasip configure 0.7.0 | |
1681 | telepathy-sofiasip configure 0.7.1 | |
1682 | 1682 | generated by GNU Autoconf 2.67 |
1683 | 1683 | |
1684 | 1684 | Copyright (C) 2010 Free Software Foundation, Inc. |
1956 | 1956 | This file contains any messages produced by compilers while |
1957 | 1957 | running configure, to aid debugging if configure makes a mistake. |
1958 | 1958 | |
1959 | It was created by telepathy-sofiasip $as_me 0.7.0, which was | |
1959 | It was created by telepathy-sofiasip $as_me 0.7.1, which was | |
1960 | 1960 | generated by GNU Autoconf 2.67. Invocation command line was |
1961 | 1961 | |
1962 | 1962 | $ $0 $@ |
2310 | 2310 | PACKAGE=telepathy-sofiasip |
2311 | 2311 | TELEPATHY_SIP_VERSION_MAJOR=0 |
2312 | 2312 | TELEPATHY_SIP_VERSION_MINOR=7 |
2313 | TELEPATHY_SIP_VERSION_MICRO=0 | |
2313 | TELEPATHY_SIP_VERSION_MICRO=1 | |
2314 | 2314 | NANO=0 |
2315 | 2315 | TELEPATHY_SIP_VERSION_NANO=$NANO |
2316 | 2316 | if test "x$NANO" = "x" || test "x$NANO" = "x0"; |
2317 | 2317 | then |
2318 | 2318 | { $as_echo "$as_me:${as_lineno-$LINENO}: configuring telepathy-sofiasip for release" >&5 |
2319 | 2319 | $as_echo "$as_me: configuring telepathy-sofiasip for release" >&6;} |
2320 | VERSION=0.7.0 | |
2320 | VERSION=0.7.1 | |
2321 | 2321 | TELEPATHY_SIP_VERSION_RELEASE=1 |
2322 | 2322 | WERROR="no" |
2323 | 2323 | else |
2324 | 2324 | { $as_echo "$as_me:${as_lineno-$LINENO}: configuring telepathy-sofiasip for development with nano $NANO" >&5 |
2325 | 2325 | $as_echo "$as_me: configuring telepathy-sofiasip for development with nano $NANO" >&6;} |
2326 | VERSION=0.7.0.$NANO | |
2326 | VERSION=0.7.1.$NANO | |
2327 | 2327 | TELEPATHY_SIP_VERSION_RELEASE=0.`date +%Y%m%d.%H%M%S` |
2328 | 2328 | WERROR="yes" |
2329 | 2329 | fi |
2827 | 2827 | |
2828 | 2828 | # Define the identity of the package. |
2829 | 2829 | PACKAGE='telepathy-sofiasip' |
2830 | VERSION='0.7.0' | |
2830 | VERSION='0.7.1' | |
2831 | 2831 | |
2832 | 2832 | |
2833 | 2833 | cat >>confdefs.h <<_ACEOF |
11549 | 11549 | pkg_cv_TELEPATHY_GLIB_CFLAGS="$TELEPATHY_GLIB_CFLAGS" |
11550 | 11550 | elif test -n "$PKG_CONFIG"; then |
11551 | 11551 | if test -n "$PKG_CONFIG" && \ |
11552 | { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"telepathy-glib >= 0.12\""; } >&5 | |
11553 | ($PKG_CONFIG --exists --print-errors "telepathy-glib >= 0.12") 2>&5 | |
11552 | { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"telepathy-glib >= 0.13.9\""; } >&5 | |
11553 | ($PKG_CONFIG --exists --print-errors "telepathy-glib >= 0.13.9") 2>&5 | |
11554 | 11554 | ac_status=$? |
11555 | 11555 | $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 |
11556 | 11556 | test $ac_status = 0; }; then |
11557 | pkg_cv_TELEPATHY_GLIB_CFLAGS=`$PKG_CONFIG --cflags "telepathy-glib >= 0.12" 2>/dev/null` | |
11557 | pkg_cv_TELEPATHY_GLIB_CFLAGS=`$PKG_CONFIG --cflags "telepathy-glib >= 0.13.9" 2>/dev/null` | |
11558 | 11558 | else |
11559 | 11559 | pkg_failed=yes |
11560 | 11560 | fi |
11565 | 11565 | pkg_cv_TELEPATHY_GLIB_LIBS="$TELEPATHY_GLIB_LIBS" |
11566 | 11566 | elif test -n "$PKG_CONFIG"; then |
11567 | 11567 | if test -n "$PKG_CONFIG" && \ |
11568 | { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"telepathy-glib >= 0.12\""; } >&5 | |
11569 | ($PKG_CONFIG --exists --print-errors "telepathy-glib >= 0.12") 2>&5 | |
11568 | { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"telepathy-glib >= 0.13.9\""; } >&5 | |
11569 | ($PKG_CONFIG --exists --print-errors "telepathy-glib >= 0.13.9") 2>&5 | |
11570 | 11570 | ac_status=$? |
11571 | 11571 | $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 |
11572 | 11572 | test $ac_status = 0; }; then |
11573 | pkg_cv_TELEPATHY_GLIB_LIBS=`$PKG_CONFIG --libs "telepathy-glib >= 0.12" 2>/dev/null` | |
11573 | pkg_cv_TELEPATHY_GLIB_LIBS=`$PKG_CONFIG --libs "telepathy-glib >= 0.13.9" 2>/dev/null` | |
11574 | 11574 | else |
11575 | 11575 | pkg_failed=yes |
11576 | 11576 | fi |
11590 | 11590 | _pkg_short_errors_supported=no |
11591 | 11591 | fi |
11592 | 11592 | if test $_pkg_short_errors_supported = yes; then |
11593 | TELEPATHY_GLIB_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "telepathy-glib >= 0.12" 2>&1` | |
11593 | TELEPATHY_GLIB_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "telepathy-glib >= 0.13.9" 2>&1` | |
11594 | 11594 | else |
11595 | TELEPATHY_GLIB_PKG_ERRORS=`$PKG_CONFIG --print-errors "telepathy-glib >= 0.12" 2>&1` | |
11595 | TELEPATHY_GLIB_PKG_ERRORS=`$PKG_CONFIG --print-errors "telepathy-glib >= 0.13.9" 2>&1` | |
11596 | 11596 | fi |
11597 | 11597 | # Put the nasty error message in config.log where it belongs |
11598 | 11598 | echo "$TELEPATHY_GLIB_PKG_ERRORS" >&5 |
11599 | 11599 | |
11600 | as_fn_error $? "Package requirements (telepathy-glib >= 0.12) were not met: | |
11600 | as_fn_error $? "Package requirements (telepathy-glib >= 0.13.9) were not met: | |
11601 | 11601 | |
11602 | 11602 | $TELEPATHY_GLIB_PKG_ERRORS |
11603 | 11603 | |
12550 | 12550 | # report actual input values of CONFIG_FILES etc. instead of their |
12551 | 12551 | # values after options handling. |
12552 | 12552 | ac_log=" |
12553 | This file was extended by telepathy-sofiasip $as_me 0.7.0, which was | |
12553 | This file was extended by telepathy-sofiasip $as_me 0.7.1, which was | |
12554 | 12554 | generated by GNU Autoconf 2.67. Invocation command line was |
12555 | 12555 | |
12556 | 12556 | CONFIG_FILES = $CONFIG_FILES |
12616 | 12616 | cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 |
12617 | 12617 | ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" |
12618 | 12618 | ac_cs_version="\\ |
12619 | telepathy-sofiasip config.status 0.7.0 | |
12619 | telepathy-sofiasip config.status 0.7.1 | |
12620 | 12620 | configured by $0, generated by GNU Autoconf 2.67, |
12621 | 12621 | with options \\"\$ac_cs_config\\" |
12622 | 12622 |
2 | 2 | m4_define([THIS_PACKAGE],[telepathy-sofiasip]) |
3 | 3 | m4_define([VERSION_MAJOR],[0]) |
4 | 4 | m4_define([VERSION_MINOR],[7]) |
5 | m4_define([VERSION_MICRO],[0]) | |
5 | m4_define([VERSION_MICRO],[1]) | |
6 | 6 | m4_define([VERSION_NANO],[0]) |
7 | 7 | |
8 | 8 | m4_define([BASE_VERSION],[VERSION_MAJOR.VERSION_MINOR.VERSION_MICRO]) |
84 | 84 | AC_SUBST(SOFIA_SIP_UA_VERSION) |
85 | 85 | |
86 | 86 | dnl Check for telepathy-glib |
87 | PKG_CHECK_MODULES(TELEPATHY_GLIB, [telepathy-glib >= 0.12]) | |
87 | PKG_CHECK_MODULES(TELEPATHY_GLIB, [telepathy-glib >= 0.13.9]) | |
88 | 88 | AC_SUBST(TELEPATHY_GLIB_CFLAGS) |
89 | 89 | AC_SUBST(TELEPATHY_GLIB_LIBS) |
90 | 90 |
356 | 356 | DEBUG("Got incoming invite from <%s>", |
357 | 357 | tp_handle_inspect (contact_repo, handle)); |
358 | 358 | |
359 | if (handle == conn->self_handle) | |
360 | { | |
361 | DEBUG("cannot handle calls from self"); | |
362 | nua_respond (ev->nua_handle, 501, "Calls from self are not supported", TAG_END()); | |
363 | return TRUE; | |
364 | } | |
365 | ||
359 | 366 | channel = new_media_channel (fac, handle, handle, channel_flags); |
360 | 367 | |
361 | 368 | tp_handle_unref (contact_repo, handle); |
313 | 313 | if (tpsip_params[i].offset == PARAM_SET_SEPARATELY) |
314 | 314 | { |
315 | 315 | DEBUG ("Parameter %s is handled specially", tpsip_params[i].name); |
316 | break; | |
316 | continue; | |
317 | 317 | } |
318 | 318 | |
319 | 319 | g_assert (tpsip_params[i].offset == PARAM_EASY); |
438 | 438 | } |
439 | 439 | } |
440 | 440 | |
441 | static GStrv | |
442 | dup_authentication_types (TpBaseProtocol *base) | |
443 | { | |
444 | const gchar * const types[] = { | |
445 | TP_IFACE_CHANNEL_INTERFACE_SASL_AUTHENTICATION, | |
446 | NULL | |
447 | }; | |
448 | ||
449 | return g_strdupv ((GStrv) types); | |
450 | } | |
451 | ||
441 | 452 | static void |
442 | 453 | tpsip_protocol_get_property (GObject *object, |
443 | 454 | guint property_id, |
493 | 504 | base_class->identify_account = identify_account; |
494 | 505 | base_class->get_interfaces = get_interfaces; |
495 | 506 | base_class->get_connection_details = get_connection_details; |
507 | base_class->dup_authentication_types = dup_authentication_types; | |
496 | 508 | |
497 | 509 | object_class->get_property = tpsip_protocol_get_property; |
498 | 510 | object_class->set_property = tpsip_protocol_set_property; |
26 | 26 | #include <tpsip/sofia-decls.h> |
27 | 27 | #include <sofia-sip/sresolv.h> |
28 | 28 | |
29 | #include <telepathy-glib/simple-password-manager.h> | |
30 | ||
29 | 31 | #ifdef HAVE_LIBIPHB |
30 | 32 | #include <libiphb.h> |
31 | 33 | #endif |
50 | 52 | gchar *registrar_realm; |
51 | 53 | |
52 | 54 | TpsipMediaFactory *media_factory; |
55 | TpSimplePasswordManager *password_manager; | |
53 | 56 | |
54 | 57 | gchar *address; |
55 | 58 | gchar *auth_user; |
159 | 159 | "connection", self, NULL); |
160 | 160 | g_ptr_array_add (channel_managers, priv->media_factory); |
161 | 161 | |
162 | priv->password_manager = tp_simple_password_manager_new ( | |
163 | conn); | |
164 | g_ptr_array_add (channel_managers, priv->password_manager); | |
165 | ||
162 | 166 | return channel_managers; |
163 | 167 | } |
164 | 168 | |
599 | 603 | G_STRUCT_OFFSET (TpsipConnectionClass, contacts_class)); |
600 | 604 | } |
601 | 605 | |
606 | typedef struct { | |
607 | TpsipConnection* self; | |
608 | nua_handle_t *nh; | |
609 | gchar *method; | |
610 | gchar *realm; | |
611 | gchar *user; | |
612 | } PrivHandleAuthData; | |
613 | ||
614 | static PrivHandleAuthData * | |
615 | priv_handle_auth_data_new (TpsipConnection* self, | |
616 | nua_handle_t *nh, | |
617 | const gchar *method, | |
618 | const gchar *realm, | |
619 | const gchar *user) | |
620 | { | |
621 | PrivHandleAuthData *data = g_slice_new (PrivHandleAuthData); | |
622 | ||
623 | data->self = g_object_ref (self); | |
624 | data->nh = nua_handle_ref (nh); | |
625 | data->method = g_strdup (method); | |
626 | data->realm = g_strdup (realm); | |
627 | data->user = g_strdup (user); | |
628 | ||
629 | return data; | |
630 | } | |
631 | ||
632 | static void | |
633 | priv_handle_auth_data_free (PrivHandleAuthData *data) | |
634 | { | |
635 | g_object_unref (data->self); | |
636 | nua_handle_unref (data->nh); | |
637 | g_free (data->method); | |
638 | g_free (data->realm); | |
639 | g_free (data->user); | |
640 | ||
641 | g_slice_free (PrivHandleAuthData, data); | |
642 | } | |
643 | ||
644 | static void priv_password_manager_prompt_cb (GObject *source_object, | |
645 | GAsyncResult *result, | |
646 | gpointer user_data); | |
647 | static void priv_handle_auth_continue (TpsipConnection* self, | |
648 | nua_handle_t *nh, | |
649 | const gchar *method, | |
650 | const gchar *realm, | |
651 | const gchar *user, | |
652 | const gchar *password); | |
653 | ||
602 | 654 | static gboolean |
603 | 655 | priv_handle_auth (TpsipConnection* self, |
604 | 656 | int status, |
613 | 665 | const char *realm = NULL; |
614 | 666 | const char *user = NULL; |
615 | 667 | const char *password = NULL; |
616 | gchar *auth = NULL; | |
617 | 668 | |
618 | 669 | if (status != 401 && status != 407) |
619 | 670 | return FALSE; |
638 | 689 | if (realm == NULL) |
639 | 690 | { |
640 | 691 | WARNING ("no realm presented for authentication"); |
692 | return FALSE; | |
693 | } | |
694 | ||
695 | if (method == NULL) | |
696 | { | |
697 | WARNING ("no method presented for authentication"); | |
641 | 698 | return FALSE; |
642 | 699 | } |
643 | 700 | |
674 | 731 | /* fall back to the main username */ |
675 | 732 | user = priv->auth_user; |
676 | 733 | password = priv->extra_auth_password; |
734 | if (password == NULL) | |
735 | /* note that this prevents asking the user for a password */ | |
736 | password = ""; | |
677 | 737 | |
678 | 738 | DEBUG("using the extra auth credentials"); |
679 | 739 | } |
684 | 744 | if (sipfrom && sipfrom->a_url[0].url_user) |
685 | 745 | /* or use the userpart in "From" header */ |
686 | 746 | user = sipfrom->a_url[0].url_user; |
747 | else | |
748 | return FALSE; | |
687 | 749 | } |
688 | 750 | |
689 | 751 | if (password == NULL) |
690 | password = ""; | |
752 | { | |
753 | PrivHandleAuthData *data = NULL; | |
754 | ||
755 | DEBUG("asking the user for a password."); | |
756 | data = priv_handle_auth_data_new (self, nh, method, realm, | |
757 | user); | |
758 | tp_simple_password_manager_prompt_async (priv->password_manager, | |
759 | priv_password_manager_prompt_cb, data); | |
760 | /* Promise that we'll handle it eventually, even if we end up just | |
761 | * handling it with a blank password. */ | |
762 | return TRUE; | |
763 | } | |
764 | ||
765 | priv_handle_auth_continue (self, nh, method, realm, | |
766 | user, password); | |
767 | return TRUE; | |
768 | } | |
769 | ||
770 | static void | |
771 | priv_password_manager_prompt_cb (GObject *source_object, | |
772 | GAsyncResult *result, | |
773 | gpointer user_data) | |
774 | { | |
775 | PrivHandleAuthData *data = user_data; | |
776 | GError *error = NULL; | |
777 | const GString *password_string; | |
778 | const gchar *password; | |
779 | ||
780 | password_string = tp_simple_password_manager_prompt_finish ( | |
781 | TP_SIMPLE_PASSWORD_MANAGER (source_object), result, &error); | |
782 | ||
783 | if (error != NULL) | |
784 | { | |
785 | /* we promised to handle the auth challenge in priv_handle_auth() by | |
786 | * returning TRUE, so we need to handle it anyway, even if it means | |
787 | * doing it with a blank password. | |
788 | */ | |
789 | DEBUG ("Auth channel failed: %s. Using blank password.", error->message); | |
790 | ||
791 | password = ""; | |
792 | ||
793 | g_error_free (error); | |
794 | } | |
795 | else | |
796 | { | |
797 | TpsipConnectionPrivate *priv = | |
798 | TPSIP_CONNECTION_GET_PRIVATE (data->self); | |
799 | ||
800 | password = password_string->str; | |
801 | /* also save it for later. */ | |
802 | g_free (priv->password); | |
803 | priv->password = g_strdup (password); | |
804 | } | |
805 | ||
806 | priv_handle_auth_continue (data->self, data->nh, data->method, data->realm, | |
807 | data->user, password); | |
808 | ||
809 | priv_handle_auth_data_free (data); | |
810 | } | |
811 | ||
812 | static void | |
813 | priv_handle_auth_continue (TpsipConnection* self, | |
814 | nua_handle_t *nh, | |
815 | const gchar *method, | |
816 | const gchar *realm, | |
817 | const gchar *user, | |
818 | const gchar *password) | |
819 | { | |
820 | gchar *auth = NULL; | |
691 | 821 | |
692 | 822 | /* step: if all info is available, create an authorization response */ |
693 | 823 | g_assert (realm != NULL); |
694 | if (user && method) { | |
695 | if (realm[0] == '"') | |
696 | auth = g_strdup_printf ("%s:%s:%s:%s", | |
697 | method, realm, user, password); | |
698 | else | |
699 | auth = g_strdup_printf ("%s:\"%s\":%s:%s", | |
700 | method, realm, user, password); | |
701 | ||
702 | DEBUG("%s authenticating user='%s' realm=%s", | |
703 | wa ? "server" : "proxy", user, realm); | |
704 | } | |
705 | ||
706 | if (auth == NULL) | |
707 | { | |
708 | WARNING ("authentication data are incomplete"); | |
709 | return FALSE; | |
710 | } | |
824 | g_assert (method != NULL); | |
825 | g_assert (user != NULL); | |
826 | g_assert (password != NULL); | |
827 | ||
828 | if (realm[0] == '"') | |
829 | auth = g_strdup_printf ("%s:%s:%s:%s", | |
830 | method, realm, user, password); | |
831 | else | |
832 | auth = g_strdup_printf ("%s:\"%s\":%s:%s", | |
833 | method, realm, user, password); | |
834 | ||
835 | DEBUG ("%s-authenticating user='%s' realm=%s", | |
836 | method, user, realm); | |
711 | 837 | |
712 | 838 | /* step: authenticate */ |
713 | 839 | nua_authenticate(nh, NUTAG_AUTH(auth), TAG_END()); |
714 | 840 | |
715 | 841 | g_free (auth); |
716 | ||
717 | return TRUE; | |
718 | 842 | } |
719 | 843 | |
720 | 844 | static gboolean |
190 | 190 | G_OBJECT_CLASS (tpsip_media_channel_parent_class); |
191 | 191 | TpDBusDaemon *bus; |
192 | 192 | TpHandleRepoIface *contact_repo; |
193 | TpIntSet *set; | |
193 | TpIntSet *add; | |
194 | 194 | |
195 | 195 | if (parent_object_class->constructed != NULL) |
196 | 196 | parent_object_class->constructed (obj); |
218 | 218 | g_assert (priv->initiator != 0); |
219 | 219 | tp_handle_ref (contact_repo, priv->initiator); |
220 | 220 | |
221 | set = tp_intset_new (); | |
222 | tp_intset_add (set, priv->initiator); | |
223 | ||
224 | tp_group_mixin_change_members (obj, "", set, NULL, NULL, NULL, 0, 0); | |
225 | ||
226 | tp_intset_destroy (set); | |
227 | ||
228 | /* Allow member adding; also, we implement the 0.17.6 properties */ | |
221 | add = tp_intset_new_containing (priv->initiator); | |
222 | tp_group_mixin_change_members (obj, "", add, NULL, NULL, NULL, 0, 0); | |
223 | tp_intset_destroy (add); | |
224 | ||
225 | /* We start off with lots of flags, and then delete them as we work out what | |
226 | * kind of channel we are, rather than trying to track what we need to | |
227 | * add/remove over time. We should always have the right flags before we are | |
228 | * advertised on the bus. */ | |
229 | 229 | tp_group_mixin_change_flags (obj, |
230 | TP_CHANNEL_GROUP_FLAG_CAN_ADD | TP_CHANNEL_GROUP_FLAG_PROPERTIES, 0); | |
230 | TP_CHANNEL_GROUP_FLAG_CAN_ADD | TP_CHANNEL_GROUP_FLAG_CAN_REMOVE | | |
231 | TP_CHANNEL_GROUP_FLAG_CAN_RESCIND | TP_CHANNEL_GROUP_FLAG_PROPERTIES, 0); | |
231 | 232 | } |
232 | 233 | |
233 | 234 | static void tpsip_media_channel_dispose (GObject *object); |
746 | 747 | tpsip_media_channel_get_handle (TpSvcChannel *iface, |
747 | 748 | DBusGMethodInvocation *context) |
748 | 749 | { |
749 | tp_svc_channel_return_from_get_handle (context, 0, 0); | |
750 | TpsipMediaChannel *self = TPSIP_MEDIA_CHANNEL (iface); | |
751 | TpsipMediaChannelPrivate *priv = TPSIP_MEDIA_CHANNEL_GET_PRIVATE (self); | |
752 | ||
753 | if (priv->handle != 0) | |
754 | tp_svc_channel_return_from_get_handle (context, TP_HANDLE_TYPE_CONTACT, | |
755 | priv->handle); | |
756 | else | |
757 | tp_svc_channel_return_from_get_handle (context, TP_HANDLE_TYPE_NONE, 0); | |
750 | 758 | } |
751 | 759 | |
752 | 760 | /** |
1030 | 1038 | TpsipMediaChannelPrivate *priv = TPSIP_MEDIA_CHANNEL_GET_PRIVATE (self); |
1031 | 1039 | |
1032 | 1040 | g_assert (priv->initiator != priv->handle); |
1041 | ||
1042 | /* RequestChannel(None, 0) => channel is anonymous: | |
1043 | * caller uses RequestStreams to set the peer and start the call. */ | |
1044 | if (priv->handle == 0) | |
1045 | return; | |
1033 | 1046 | |
1034 | 1047 | priv_outbound_call (self, priv->handle); |
1035 | 1048 | |
1134 | 1147 | const char* message) |
1135 | 1148 | { |
1136 | 1149 | TpGroupMixin *mixin = TP_GROUP_MIXIN (self); |
1137 | TpIntSet *set; | |
1150 | TpIntSet *remove; | |
1138 | 1151 | guint reason = TP_CHANNEL_GROUP_CHANGE_REASON_ERROR; |
1139 | 1152 | |
1140 | 1153 | switch (status) |
1171 | 1184 | if (message == NULL || !g_utf8_validate (message, -1, NULL)) |
1172 | 1185 | message = ""; |
1173 | 1186 | |
1174 | set = tp_intset_new (); | |
1175 | tp_intset_add (set, peer); | |
1176 | tp_intset_add (set, mixin->self_handle); | |
1187 | remove = tp_intset_new (); | |
1188 | tp_intset_add (remove, peer); | |
1189 | tp_intset_add (remove, mixin->self_handle); | |
1177 | 1190 | tp_group_mixin_change_members ((GObject *)self, message, |
1178 | NULL, set, NULL, NULL, peer, reason); | |
1179 | tp_intset_destroy (set); | |
1191 | NULL, remove, NULL, NULL, peer, reason); | |
1192 | tp_intset_destroy (remove); | |
1180 | 1193 | } |
1181 | 1194 | |
1182 | 1195 | guint |
1220 | 1233 | { |
1221 | 1234 | TpsipMediaChannelPrivate *priv = TPSIP_MEDIA_CHANNEL_GET_PRIVATE (self); |
1222 | 1235 | TpGroupMixin *mixin = TP_GROUP_MIXIN (self); |
1223 | TpIntSet *set; | |
1236 | TpIntSet *remove; | |
1224 | 1237 | TpHandle peer; |
1225 | 1238 | |
1226 | 1239 | g_return_val_if_fail (priv->session != NULL, FALSE); |
1227 | 1240 | |
1228 | 1241 | peer = tpsip_media_session_get_peer (priv->session); |
1229 | set = tp_intset_new (); | |
1230 | tp_intset_add (set, peer); | |
1231 | tp_intset_add (set, mixin->self_handle); | |
1232 | ||
1233 | tp_group_mixin_change_members ((GObject *) self, | |
1234 | "", | |
1235 | NULL, /* add */ | |
1236 | set, /* remove */ | |
1237 | NULL, | |
1238 | NULL, | |
1239 | peer, | |
1240 | TP_CHANNEL_GROUP_CHANGE_REASON_NONE); | |
1241 | ||
1242 | tp_intset_destroy (set); | |
1242 | remove = tp_intset_new (); | |
1243 | tp_intset_add (remove, peer); | |
1244 | tp_intset_add (remove, mixin->self_handle); | |
1245 | ||
1246 | tp_group_mixin_change_members ((GObject *) self, "", | |
1247 | NULL, remove, NULL, NULL, | |
1248 | peer, TP_CHANNEL_GROUP_CHANGE_REASON_NONE); | |
1249 | ||
1250 | tp_intset_destroy (remove); | |
1243 | 1251 | |
1244 | 1252 | return TRUE; |
1245 | 1253 | } |
1252 | 1260 | { |
1253 | 1261 | TpsipMediaChannelPrivate *priv = TPSIP_MEDIA_CHANNEL_GET_PRIVATE (self); |
1254 | 1262 | TpGroupMixin *mixin = TP_GROUP_MIXIN (self); |
1255 | TpIntSet *set; | |
1263 | TpIntSet *remove; | |
1256 | 1264 | TpHandle actor = 0; |
1257 | 1265 | TpHandle peer; |
1258 | 1266 | const sip_reason_t *reason; |
1296 | 1304 | if (message == NULL || !g_utf8_validate (message, -1, NULL)) |
1297 | 1305 | message = ""; |
1298 | 1306 | |
1299 | set = tp_intset_new (); | |
1300 | tp_intset_add (set, peer); | |
1301 | tp_intset_add (set, mixin->self_handle); | |
1302 | ||
1303 | tp_group_mixin_change_members ((GObject *) self, | |
1304 | message, | |
1305 | NULL, /* add */ | |
1306 | set, /* remove */ | |
1307 | NULL, | |
1308 | NULL, | |
1309 | actor, | |
1310 | TP_CHANNEL_GROUP_CHANGE_REASON_NONE); | |
1311 | ||
1312 | tp_intset_destroy (set); | |
1307 | remove = tp_intset_new (); | |
1308 | tp_intset_add (remove, peer); | |
1309 | tp_intset_add (remove, mixin->self_handle); | |
1310 | ||
1311 | tp_group_mixin_change_members ((GObject *) self, message, | |
1312 | NULL, remove, NULL, NULL, | |
1313 | actor, TP_CHANNEL_GROUP_CHANGE_REASON_NONE); | |
1314 | ||
1315 | tp_intset_destroy (remove); | |
1313 | 1316 | |
1314 | 1317 | return TRUE; |
1315 | 1318 | } |
1390 | 1393 | TPSIP_CHANNEL_CALL_STATE_PROCEEDING_MASK); |
1391 | 1394 | |
1392 | 1395 | if (status < 300) |
1393 | tpsip_media_session_accept (priv->session); | |
1396 | { | |
1397 | TpIntSet *add = tp_intset_new_containing (peer); | |
1398 | ||
1399 | tp_group_mixin_change_members ((GObject *) self, | |
1400 | "", | |
1401 | add, /* add */ | |
1402 | NULL, /* remove */ | |
1403 | NULL, | |
1404 | NULL, | |
1405 | peer, | |
1406 | TP_CHANNEL_GROUP_CHANGE_REASON_NONE); | |
1407 | ||
1408 | tp_intset_destroy (add); | |
1409 | ||
1410 | tpsip_media_session_accept (priv->session); | |
1411 | } | |
1394 | 1412 | else if (status == 491) |
1395 | 1413 | tpsip_media_session_resolve_glare (priv->session); |
1396 | 1414 | else |
1444 | 1462 | switch (state) |
1445 | 1463 | { |
1446 | 1464 | case TPSIP_MEDIA_SESSION_STATE_INVITE_SENT: |
1447 | set = tp_intset_new (); | |
1448 | ||
1449 | 1465 | g_assert (priv->initiator == self_handle); |
1450 | 1466 | |
1451 | 1467 | /* add the peer to remote pending */ |
1452 | tp_intset_add (set, peer); | |
1468 | set = tp_intset_new_containing (peer); | |
1453 | 1469 | tp_group_mixin_change_members ((GObject *)channel, |
1454 | 1470 | "", |
1455 | 1471 | NULL, /* add */ |
1459 | 1475 | self_handle, /* actor */ |
1460 | 1476 | TP_CHANNEL_GROUP_CHANGE_REASON_INVITED); |
1461 | 1477 | |
1462 | /* update flags: allow removal and rescinding, no more adding */ | |
1463 | tp_group_mixin_change_flags ((GObject *)channel, | |
1464 | TP_CHANNEL_GROUP_FLAG_CAN_REMOVE | TP_CHANNEL_GROUP_FLAG_CAN_RESCIND, | |
1478 | /* update flags: no more adding */ | |
1479 | tp_group_mixin_change_flags ((GObject *)channel, 0, | |
1465 | 1480 | TP_CHANNEL_GROUP_FLAG_CAN_ADD); |
1466 | 1481 | |
1467 | 1482 | break; |
1468 | 1483 | |
1469 | 1484 | case TPSIP_MEDIA_SESSION_STATE_INVITE_RECEIVED: |
1470 | set = tp_intset_new (); | |
1471 | ||
1472 | 1485 | /* add ourself to local pending */ |
1473 | tp_intset_add (set, self_handle); | |
1486 | set = tp_intset_new_containing (self_handle); | |
1474 | 1487 | tp_group_mixin_change_members ((GObject *) channel, "", |
1475 | 1488 | NULL, /* add */ |
1476 | 1489 | NULL, /* remove */ |
1479 | 1492 | priv->initiator, /* actor */ |
1480 | 1493 | TP_CHANNEL_GROUP_CHANGE_REASON_INVITED); |
1481 | 1494 | |
1482 | /* No adding more members to the incoming call, removing is OK */ | |
1483 | tp_group_mixin_change_flags ((GObject *) channel, | |
1484 | TP_CHANNEL_GROUP_FLAG_CAN_REMOVE, | |
1485 | TP_CHANNEL_GROUP_FLAG_CAN_ADD); | |
1495 | /* No adding more members to the incoming call. Therefore also not | |
1496 | * possible to add anyone to remote-pending, so rescinding would make | |
1497 | * utterly no sense. We also disallow removing the remote peer if | |
1498 | * we are not the initiator, so disallow that too. | |
1499 | * Removing yourself to end the call is not represented by group flags. | |
1500 | */ | |
1501 | tp_group_mixin_change_flags ((GObject *) channel, 0, | |
1502 | TP_CHANNEL_GROUP_FLAG_CAN_ADD | TP_CHANNEL_GROUP_FLAG_CAN_REMOVE | | |
1503 | TP_CHANNEL_GROUP_FLAG_CAN_RESCIND); | |
1486 | 1504 | |
1487 | 1505 | break; |
1488 | 1506 | |
1492 | 1510 | if (!tp_handle_set_is_member (mixin->remote_pending, peer)) |
1493 | 1511 | break; /* no-op */ |
1494 | 1512 | |
1495 | set = tp_intset_new (); | |
1496 | ||
1497 | 1513 | /* the peer has promoted itself to members */ |
1498 | tp_intset_add (set, peer); | |
1514 | set = tp_intset_new_containing (peer); | |
1499 | 1515 | tp_group_mixin_change_members ((GObject *)channel, "", |
1500 | 1516 | set, /* add */ |
1501 | 1517 | NULL, /* remove */ |
1508 | 1524 | if (!tp_handle_set_is_member (mixin->local_pending, self_handle)) |
1509 | 1525 | break; /* no-op */ |
1510 | 1526 | |
1511 | set = tp_intset_new (); | |
1512 | ||
1513 | 1527 | /* promote ourselves to members */ |
1514 | tp_intset_add (set, self_handle); | |
1528 | set = tp_intset_new_containing (self_handle); | |
1515 | 1529 | tp_group_mixin_change_members ((GObject *)channel, "", |
1516 | 1530 | set, /* add */ |
1517 | 1531 | NULL, /* remove */ |
1520 | 1534 | self_handle, 0); |
1521 | 1535 | } |
1522 | 1536 | |
1523 | /* update flags: allow removal, deny adding and rescinding */ | |
1524 | tp_group_mixin_change_flags ((GObject *)channel, | |
1525 | TP_CHANNEL_GROUP_FLAG_CAN_REMOVE, | |
1526 | TP_CHANNEL_GROUP_FLAG_CAN_ADD | |
1527 | | TP_CHANNEL_GROUP_FLAG_CAN_RESCIND); | |
1537 | /* update flags: deny adding and rescinding. Removing the remote peer is | |
1538 | * still allowed. | |
1539 | * Removing yourself to end the call is not represented by group flags. | |
1540 | */ | |
1541 | tp_group_mixin_change_flags ((GObject *)channel, 0, | |
1542 | TP_CHANNEL_GROUP_FLAG_CAN_ADD | TP_CHANNEL_GROUP_FLAG_CAN_RESCIND); | |
1528 | 1543 | |
1529 | 1544 | break; |
1530 | 1545 | |
1716 | 1731 | |
1717 | 1732 | if (priv->initiator == mixin->self_handle) |
1718 | 1733 | { |
1719 | TpIntSet *set; | |
1734 | TpIntSet *remote_pending; | |
1720 | 1735 | |
1721 | 1736 | /* case a: an old-school outbound call |
1722 | 1737 | * (we are the initiator, a new handle added with AddMembers) */ |
1726 | 1741 | /* Backwards compatible behavior: |
1727 | 1742 | * add the peer to remote pending without waiting for the actual request |
1728 | 1743 | * to be sent */ |
1729 | set = tp_intset_new (); | |
1730 | tp_intset_add (set, handle); | |
1744 | remote_pending = tp_intset_new_containing (handle); | |
1731 | 1745 | tp_group_mixin_change_members (iface, |
1732 | 1746 | "", |
1733 | 1747 | NULL, /* add */ |
1734 | 1748 | NULL, /* remove */ |
1735 | 1749 | NULL, /* local pending */ |
1736 | set, /* remote pending */ | |
1750 | remote_pending, /* remote pending */ | |
1737 | 1751 | mixin->self_handle, /* actor */ |
1738 | 1752 | TP_CHANNEL_GROUP_CHANGE_REASON_INVITED); |
1739 | tp_intset_destroy (set); | |
1740 | ||
1741 | /* update flags: allow removal and rescinding, no more adding */ | |
1742 | tp_group_mixin_change_flags (iface, | |
1743 | TP_CHANNEL_GROUP_FLAG_CAN_REMOVE | TP_CHANNEL_GROUP_FLAG_CAN_RESCIND, | |
1753 | tp_intset_destroy (remote_pending); | |
1754 | ||
1755 | /* update flags: no more adding. | |
1756 | * Removal and rescinding are still allowed. */ | |
1757 | tp_group_mixin_change_flags (iface, 0, | |
1744 | 1758 | TP_CHANNEL_GROUP_FLAG_CAN_ADD); |
1745 | 1759 | |
1746 | 1760 | return TRUE; |
42 | 42 | #include "sip-connection.h" |
43 | 43 | #include "sip-connection-helpers.h" |
44 | 44 | |
45 | #include <sofia-sip/sip_protos.h> | |
45 | 46 | #include <sofia-sip/sip_status.h> |
46 | 47 | |
47 | 48 | #define DEBUG_FLAG TPSIP_DEBUG_IM |
879 | 880 | } |
880 | 881 | |
881 | 882 | void tpsip_text_channel_receive(TpsipTextChannel *chan, |
882 | nua_t *nua, | |
883 | const sip_t *sip, | |
883 | 884 | TpHandle sender, |
884 | 885 | const char *text, |
885 | 886 | gsize len) |
887 | 888 | TpsipTextChannelPrivate *priv = TPSIP_TEXT_CHANNEL_GET_PRIVATE (chan); |
888 | 889 | TpMessage *msg; |
889 | 890 | TpBaseConnection *base_conn; |
891 | sip_call_id_t *hdr_call_id; | |
892 | sip_cseq_t *hdr_cseq; | |
893 | sip_date_t *hdr_date_sent; | |
890 | 894 | |
891 | 895 | base_conn = (TpBaseConnection *) priv->conn; |
892 | 896 | msg = tp_message_new (base_conn, 2, 2); |
896 | 900 | /* Header */ |
897 | 901 | tp_message_set_handle (msg, 0, "message-sender", TP_HANDLE_TYPE_CONTACT, |
898 | 902 | sender); |
899 | tp_message_set_uint64 (msg, 0, "message-received", time (NULL)); | |
903 | tp_message_set_int64 (msg, 0, "message-received", time (NULL)); | |
904 | ||
905 | hdr_date_sent = sip_date (sip); | |
906 | if (hdr_date_sent != NULL) | |
907 | { | |
908 | tp_message_set_int64 (msg, 0, "message-sent", | |
909 | hdr_date_sent->d_time - SU_TIME_EPOCH); | |
910 | } | |
911 | ||
912 | /* Create a message token out of globally unique SIP header values. | |
913 | * As MESSAGE requests can be sent within a dialog, we have to append | |
914 | * the Call-ID value with the sequence number in CSeq. */ | |
915 | hdr_call_id = sip_call_id (sip); | |
916 | hdr_cseq = sip_cseq (sip); | |
917 | if (hdr_call_id != NULL && hdr_cseq != NULL) | |
918 | { | |
919 | tp_message_set_string_printf (msg, 0, "message-token", "%s;cseq=%u", | |
920 | hdr_call_id->i_id, (guint) hdr_cseq->cs_seq); | |
921 | } | |
900 | 922 | |
901 | 923 | /* Body */ |
902 | 924 | tp_message_set_string (msg, 1, "content-type", "text/plain"); |
61 | 61 | (G_TYPE_INSTANCE_GET_CLASS ((obj), TPSIP_TYPE_TEXT_CHANNEL, TpsipTextChannelClass)) |
62 | 62 | |
63 | 63 | void tpsip_text_channel_receive (TpsipTextChannel *obj, |
64 | nua_t *nua, | |
64 | const sip_t *sip, | |
65 | 65 | TpHandle sender, |
66 | 66 | const char *text, |
67 | 67 | gsize len); |
585 | 585 | handle, handle, NULL); |
586 | 586 | |
587 | 587 | tpsip_text_channel_receive (channel, |
588 | ev->nua, handle, text, len); | |
588 | sip, handle, text, len); | |
589 | 589 | |
590 | 590 | tp_handle_unref (contact_repo, handle); |
591 | 591 |
0 | NULL = | |
1 | ||
0 | 2 | TWISTED_TESTS = \ |
1 | 3 | cm/protocol.py \ |
2 | 4 | test-register.py \ |
3 | 5 | test-register-fail.py \ |
6 | test-register-sasl.py \ | |
4 | 7 | test-handle-normalisation.py \ |
5 | 8 | test-message.py \ |
6 | 9 | test-self-alias.py \ |
7 | text/initiate-requestotron.py | |
10 | text/initiate-requestotron.py \ | |
11 | voip/incoming-basics.py \ | |
12 | voip/outgoing-basics.py \ | |
13 | $(NULL) | |
8 | 14 | |
9 | 15 | TESTS = |
10 | 16 | |
29 | 35 | $(TWISTED_TESTS) \ |
30 | 36 | constants.py \ |
31 | 37 | sofiatest.py \ |
32 | servicetest.py | |
38 | servicetest.py \ | |
39 | voip/voip_test.py | |
33 | 40 | |
34 | 41 | CLEANFILES = sofiasip-[1-9]*.log *.pyc */*.pyc |
35 | 42 |
247 | 247 | top_build_prefix = @top_build_prefix@ |
248 | 248 | top_builddir = @top_builddir@ |
249 | 249 | top_srcdir = @top_srcdir@ |
250 | NULL = | |
250 | 251 | TWISTED_TESTS = \ |
251 | 252 | cm/protocol.py \ |
252 | 253 | test-register.py \ |
253 | 254 | test-register-fail.py \ |
255 | test-register-sasl.py \ | |
254 | 256 | test-handle-normalisation.py \ |
255 | 257 | test-message.py \ |
256 | 258 | test-self-alias.py \ |
257 | text/initiate-requestotron.py | |
259 | text/initiate-requestotron.py \ | |
260 | voip/incoming-basics.py \ | |
261 | voip/outgoing-basics.py \ | |
262 | $(NULL) | |
258 | 263 | |
259 | 264 | TESTS_ENVIRONMENT = \ |
260 | 265 | PYTHONPATH=@abs_top_srcdir@/tests/twisted |
264 | 269 | $(TWISTED_TESTS) \ |
265 | 270 | constants.py \ |
266 | 271 | sofiatest.py \ |
267 | servicetest.py | |
272 | servicetest.py \ | |
273 | voip/voip_test.py | |
268 | 274 | |
269 | 275 | CLEANFILES = sofiasip-[1-9]*.log *.pyc */*.pyc |
270 | 276 | check_misc_sources = $(TESTS) |
8 | 8 | |
9 | 9 | import os |
10 | 10 | import sys |
11 | import random | |
12 | ||
11 | 13 | import dbus |
12 | 14 | import dbus.glib |
13 | 15 | |
19 | 21 | |
20 | 22 | def register(self, message, host, port): |
21 | 23 | if hasattr(self, 'registrar_handler'): |
24 | self.event_func(servicetest.Event('sip-register', | |
25 | uri=str(message.uri), headers=message.headers, body=message.body, | |
26 | sip_message=message, host=host, port=port)) | |
22 | 27 | if self.registrar_handler(message, host, port): |
23 | 28 | sip.RegisterProxy.register(self, message, host, port) |
24 | 29 | else: |
27 | 32 | def handle_request(self, message, addr): |
28 | 33 | if message.method == 'REGISTER': |
29 | 34 | return sip.RegisterProxy.handle_request(self, message, addr) |
30 | if message.method == 'MESSAGE': | |
31 | self.event_func(servicetest.Event('sip-message', | |
35 | elif message.method == 'OPTIONS' and \ | |
36 | 'REGISTRATION PROBE' == message.headers.get('subject','')[0]: | |
37 | self.deliverResponse(self.responseFromRequest(200, message)) | |
38 | else: | |
39 | headers = {} | |
40 | for key, values in message.headers.items(): | |
41 | headers[key.replace('-', '_')] = values[0] | |
42 | self.event_func(servicetest.Event('sip-%s' % message.method.lower(), | |
32 | 43 | uri=str(message.uri), headers=message.headers, body=message.body, |
33 | sip_message=message)) | |
44 | sip_message=message, **headers)) | |
34 | 45 | |
35 | 46 | def handle_response(self, message, addr): |
47 | headers = {} | |
48 | for key, values in message.headers.items(): | |
49 | headers[key.replace('-', '_')] = values[0] | |
36 | 50 | self.event_func(servicetest.Event('sip-response', |
37 | 51 | code=message.code, headers=message.headers, body=message.body, |
38 | sip_message=message)) | |
52 | sip_message=message, **headers)) | |
39 | 53 | |
40 | 54 | def prepare_test(event_func, register_cb, params=None): |
41 | 55 | actual_params = { |
42 | 56 | 'account': 'testacc@127.0.0.1', |
43 | 57 | 'password': 'testpwd', |
44 | 58 | 'proxy-host': '127.0.0.1', |
45 | 'port': dbus.UInt16(9090), | |
59 | 'port': dbus.UInt16(random.randint(9090, 9999)), | |
46 | 60 | 'local-ip-address': '127.0.0.1' |
47 | 61 | } |
48 | 62 | |
49 | 63 | if params is not None: |
50 | actual_params.update(params) | |
64 | for k, v in params.items(): | |
65 | if v is None: | |
66 | actual_params.pop(k, None) | |
67 | else: | |
68 | actual_params[k] = v | |
51 | 69 | |
52 | 70 | bus = dbus.SessionBus() |
53 | 71 | conn = servicetest.make_connection(bus, event_func, |
106 | 124 | return '\x1b[32m%s\x1b[0m' % s |
107 | 125 | |
108 | 126 | patterns = { |
109 | 'handled': green, | |
110 | 'not handled': red, | |
127 | 'handled,': green, | |
128 | 'not hand': red, | |
111 | 129 | } |
112 | 130 | |
113 | 131 | class Colourer: |
116 | 134 | self.patterns = patterns |
117 | 135 | |
118 | 136 | def write(self, s): |
119 | f = self.patterns.get(s, lambda x: x) | |
137 | f = self.patterns.get(s[:len('handled,')], lambda x: x) | |
120 | 138 | self.fh.write(f(s)) |
139 | ||
140 | def isatty(self): | |
141 | return False | |
121 | 142 | |
122 | 143 | sys.stdout = Colourer(sys.stdout, patterns) |
123 | 144 |
5 | 5 | import twisted.protocols.sip |
6 | 6 | |
7 | 7 | import dbus |
8 | import email.utils | |
9 | import time | |
8 | 10 | import uuid |
9 | 11 | |
10 | 12 | # Test message channels |
84 | 86 | |
85 | 87 | conn.ReleaseHandles(1, [handle]) |
86 | 88 | |
87 | url = twisted.protocols.sip.parseURL(self_uri) | |
88 | msg = twisted.protocols.sip.Request('MESSAGE', url) | |
89 | send_message(sip, ua_via, 'Hi') | |
89 | call_id = 'XYZ@localhost' | |
90 | send_message(sip, ua_via, 'Hi', call_id=call_id, time=1234567890) | |
90 | 91 | |
91 | 92 | incoming_obj, handle = test_new_channel (q, bus, conn, |
92 | 93 | target_uri=FROM_URL, |
98 | 99 | name = conn.InspectHandles(1, [handle])[0] |
99 | 100 | assert name == FROM_URL |
100 | 101 | |
101 | event = q.expect('dbus-signal', signal='Received') | |
102 | assert event.args[5] == 'Hi' | |
102 | event = q.expect('dbus-signal', signal='MessageReceived') | |
103 | msg = event.args[0] | |
104 | now = time.time() | |
105 | assert msg[0]['message-token'] == "%s;cseq=%u" % (call_id, cseq_num) | |
106 | assert now - 10 < msg[0]['message-received'] < now + 10 | |
107 | assert msg[0]['message-sent'] == 1234567890 | |
108 | assert msg[1]['content-type'] == 'text/plain' | |
109 | assert msg[1]['content'] == 'Hi' | |
103 | 110 | |
104 | 111 | # FIXME: times out for some reason, the response is in fact sent; |
105 | 112 | # race condition with the earlier wait for 'dbus-signal'? |
106 | 113 | #event = q.expect('sip-response', code=200) |
107 | 114 | |
108 | iface.AcknowledgePendingMessages([event.args[0]]) | |
115 | iface.AcknowledgePendingMessages([msg[0]['pending-message-id']]) | |
109 | 116 | |
110 | 117 | # Test conversion from an 8-bit encoding. |
111 | 118 | # Due to limited set of encodings available in some environments, |
194 | 201 | q.expect('dbus-signal', signal='StatusChanged', args=[2,1]) |
195 | 202 | |
196 | 203 | cseq_num = 1 |
197 | def send_message(sip, destVia, body, encoding=None, sender=FROM_URL): | |
204 | def send_message(sip, destVia, body, | |
205 | encoding=None, sender=FROM_URL, call_id=None, time=None): | |
198 | 206 | global cseq_num |
199 | 207 | cseq_num += 1 |
200 | 208 | url = twisted.protocols.sip.parseURL('sip:testacc@127.0.0.1') |
209 | 217 | else: |
210 | 218 | msg.addHeader('content-type', 'text/plain; charset=%s' % encoding) |
211 | 219 | msg.addHeader('content-length', '%d' % len(msg.body)) |
212 | msg.addHeader('call-id', uuid.uuid4().hex) | |
220 | msg.addHeader('call-id', call_id or uuid.uuid4().hex) | |
221 | if time is not None: | |
222 | msg.addHeader('date', email.utils.formatdate(time, False, True)) | |
213 | 223 | via = sip.getVia() |
214 | 224 | via.branch = 'z9hG4bKXYZ' |
215 | 225 | msg.addHeader('via', via.toString()) |
0 | """ | |
1 | Test SIP registration failure. | |
2 | """ | |
3 | ||
4 | import dbus | |
5 | ||
6 | from sofiatest import exec_test | |
7 | ||
8 | def test(q, bus, conn, sip): | |
9 | conn.Connect() | |
10 | q.expect('dbus-signal', signal='StatusChanged', args=[1, 1]) | |
11 | ||
12 | q.expect('sip-register') | |
13 | ||
14 | nc = q.expect('dbus-signal', signal='NewChannels') | |
15 | (((path, props),),) = nc.args | |
16 | assert props['org.freedesktop.Telepathy.Channel.ChannelType'] == \ | |
17 | 'org.freedesktop.Telepathy.Channel.Type.ServerAuthentication' | |
18 | assert props['org.freedesktop.Telepathy.Channel.Interface.SASLAuthentication.AvailableMechanisms'] == \ | |
19 | ['X-TELEPATHY-PASSWORD'] | |
20 | ||
21 | chan = dbus.Interface(bus.get_object(conn._named_service, path), | |
22 | "org.freedesktop.Telepathy.Channel.Interface.SASLAuthentication") | |
23 | ||
24 | chan.StartMechanismWithData('X-TELEPATHY-PASSWORD', 'wrong password') | |
25 | chan.AcceptSASL() | |
26 | ||
27 | q.expect('sip-register') | |
28 | ||
29 | q.expect('dbus-signal', signal='StatusChanged', args=[2, 3]) | |
30 | return True | |
31 | ||
32 | if __name__ == '__main__': | |
33 | exec_test(test, register_cb=lambda *args: False, | |
34 | params={"password": None}) | |
35 |
12 | 12 | return True |
13 | 13 | |
14 | 14 | if __name__ == '__main__': |
15 | exec_test(test) | |
15 | exec_test(test, params={"password": None}) | |
16 | 16 |
0 | """ | |
1 | Test incoming call handling. | |
2 | """ | |
3 | ||
4 | import dbus | |
5 | ||
6 | from sofiatest import exec_test | |
7 | from servicetest import ( | |
8 | make_channel_proxy, wrap_channel, | |
9 | EventPattern, call_async, | |
10 | assertEquals, assertContains, assertLength, | |
11 | ) | |
12 | import constants as cs | |
13 | from voip_test import VoipTestContext | |
14 | ||
15 | def test(q, bus, conn, sip_proxy, peer='foo@bar.com'): | |
16 | conn.Connect() | |
17 | q.expect('dbus-signal', signal='StatusChanged', args=[0, 1]) | |
18 | ||
19 | context = VoipTestContext(q, conn, bus, sip_proxy, 'sip:testacc@127.0.0.1', peer) | |
20 | ||
21 | self_handle = conn.GetSelfHandle() | |
22 | remote_handle = conn.RequestHandles(cs.HT_CONTACT, [context.peer])[0] | |
23 | ||
24 | # Try making a call to ourself. StreamedMedia should refuse this because | |
25 | # the API doesn't support it. | |
26 | context.incoming_call_from_self() | |
27 | q.expect('sip-response', code=501) | |
28 | ||
29 | # Remote end calls us | |
30 | context.incoming_call() | |
31 | ||
32 | nc, e = q.expect_many( | |
33 | EventPattern('dbus-signal', signal='NewChannels'), | |
34 | EventPattern('dbus-signal', signal='NewSessionHandler'), | |
35 | )[0:2] | |
36 | ||
37 | path, props = nc.args[0][0] | |
38 | ct = props[cs.CHANNEL_TYPE] | |
39 | ht = props[cs.CHANNEL + '.TargetHandleType'] | |
40 | h = props[cs.CHANNEL + '.TargetHandle'] | |
41 | ||
42 | assert ct == cs.CHANNEL_TYPE_STREAMED_MEDIA, ct | |
43 | assert ht == cs.HT_CONTACT, ht | |
44 | assert h == remote_handle, h | |
45 | ||
46 | media_chan = make_channel_proxy(conn, path, 'Channel.Interface.Group') | |
47 | media_iface = make_channel_proxy(conn, path, 'Channel.Type.StreamedMedia') | |
48 | ||
49 | # S-E was notified about new session handler, and calls Ready on it | |
50 | assert e.args[1] == 'rtp' | |
51 | session_handler = make_channel_proxy(conn, e.args[0], 'Media.SessionHandler') | |
52 | session_handler.Ready() | |
53 | ||
54 | nsh_event = q.expect('dbus-signal', signal='NewStreamHandler') | |
55 | ||
56 | # S-E gets notified about a newly-created stream | |
57 | stream_handler = make_channel_proxy(conn, nsh_event.args[0], | |
58 | 'Media.StreamHandler') | |
59 | ||
60 | streams = media_iface.ListStreams() | |
61 | assertLength(1, streams) | |
62 | ||
63 | stream_id, stream_handle, stream_type, _, stream_direction, pending_flags =\ | |
64 | streams[0] | |
65 | assertEquals(remote_handle, stream_handle) | |
66 | assertEquals(cs.MEDIA_STREAM_TYPE_AUDIO, stream_type) | |
67 | assertEquals(cs.MEDIA_STREAM_DIRECTION_RECEIVE, stream_direction) | |
68 | assertEquals(cs.MEDIA_STREAM_PENDING_LOCAL_SEND, pending_flags) | |
69 | ||
70 | # Exercise channel properties | |
71 | channel_props = media_chan.GetAll( | |
72 | cs.CHANNEL, dbus_interface=dbus.PROPERTIES_IFACE) | |
73 | assertEquals(remote_handle, channel_props['TargetHandle']) | |
74 | assertEquals(cs.HT_CONTACT, channel_props['TargetHandleType']) | |
75 | assertEquals((cs.HT_CONTACT, remote_handle), | |
76 | media_chan.GetHandle(dbus_interface=cs.CHANNEL)) | |
77 | assertEquals(context.peer_id, channel_props['TargetID']) | |
78 | assertEquals(context.peer_id, channel_props['InitiatorID']) | |
79 | assertEquals(remote_handle, channel_props['InitiatorHandle']) | |
80 | assertEquals(False, channel_props['Requested']) | |
81 | ||
82 | group_props = media_chan.GetAll( | |
83 | cs.CHANNEL_IFACE_GROUP, dbus_interface=dbus.PROPERTIES_IFACE) | |
84 | ||
85 | assert group_props['SelfHandle'] == self_handle, \ | |
86 | (group_props['SelfHandle'], self_handle) | |
87 | ||
88 | flags = group_props['GroupFlags'] | |
89 | assert flags & cs.GF_PROPERTIES, flags | |
90 | # Changing members in any way other than adding or removing yourself is | |
91 | # meaningless for incoming calls, and the flags need not be sent to change | |
92 | # your own membership. | |
93 | assert not flags & cs.GF_CAN_ADD, flags | |
94 | assert not flags & cs.GF_CAN_REMOVE, flags | |
95 | assert not flags & cs.GF_CAN_RESCIND, flags | |
96 | ||
97 | assert group_props['Members'] == [remote_handle], group_props['Members'] | |
98 | assert group_props['RemotePendingMembers'] == [], \ | |
99 | group_props['RemotePendingMembers'] | |
100 | # We're local pending because remote_handle invited us. | |
101 | assert group_props['LocalPendingMembers'] == \ | |
102 | [(self_handle, remote_handle, cs.GC_REASON_INVITED, '')], \ | |
103 | unwrap(group_props['LocalPendingMembers']) | |
104 | ||
105 | streams = media_chan.ListStreams( | |
106 | dbus_interface=cs.CHANNEL_TYPE_STREAMED_MEDIA) | |
107 | assert len(streams) == 1, streams | |
108 | assert len(streams[0]) == 6, streams[0] | |
109 | # streams[0][0] is the stream identifier, which in principle we can't | |
110 | # make any assertion about (although in practice it's probably 1) | |
111 | assert streams[0][1] == remote_handle, (streams[0], remote_handle) | |
112 | assert streams[0][2] == cs.MEDIA_STREAM_TYPE_AUDIO, streams[0] | |
113 | # We haven't connected yet | |
114 | assert streams[0][3] == cs.MEDIA_STREAM_STATE_DISCONNECTED, streams[0] | |
115 | # In Gabble, incoming streams start off with remote send enabled, and | |
116 | # local send requested | |
117 | assert streams[0][4] == cs.MEDIA_STREAM_DIRECTION_RECEIVE, streams[0] | |
118 | assert streams[0][5] == cs.MEDIA_STREAM_PENDING_LOCAL_SEND, streams[0] | |
119 | ||
120 | # Connectivity checks happen before we have accepted the call | |
121 | stream_handler.NewNativeCandidate("fake", context.get_remote_transports_dbus()) | |
122 | stream_handler.NativeCandidatesPrepared() | |
123 | stream_handler.Ready(context.get_audio_codecs_dbus()) | |
124 | stream_handler.StreamState(cs.MEDIA_STREAM_STATE_CONNECTED) | |
125 | stream_handler.SupportedCodecs(context.get_audio_codecs_dbus()) | |
126 | ||
127 | # At last, accept the call | |
128 | media_chan.AddMembers([self_handle], 'accepted') | |
129 | ||
130 | # Call is accepted, we become a member, and the stream that was pending | |
131 | # local send is now sending. | |
132 | memb, acc, _, _, _ = q.expect_many( | |
133 | EventPattern('dbus-signal', signal='MembersChanged', | |
134 | args=[u'', [self_handle], [], [], [], self_handle, | |
135 | cs.GC_REASON_NONE]), | |
136 | EventPattern('sip-response', call_id=context.call_id, code=200), | |
137 | EventPattern('dbus-signal', signal='SetStreamSending', args=[True]), | |
138 | EventPattern('dbus-signal', signal='SetStreamPlaying', args=[True]), | |
139 | EventPattern('dbus-signal', signal='StreamDirectionChanged', | |
140 | args=[stream_id, cs.MEDIA_STREAM_DIRECTION_BIDIRECTIONAL, 0]), | |
141 | ) | |
142 | ||
143 | context.check_call_sdp(acc.sip_message.body) | |
144 | ||
145 | context.ack(acc.sip_message) | |
146 | ||
147 | # we are now both in members | |
148 | members = media_chan.GetMembers() | |
149 | assert set(members) == set([self_handle, remote_handle]), members | |
150 | ||
151 | # Connected! Blah, blah, ... | |
152 | ||
153 | # 'Nuff said | |
154 | bye_msg = context.terminate() | |
155 | ||
156 | q.expect_many(EventPattern('dbus-signal', signal='Closed', path=path), | |
157 | EventPattern('sip-response', cseq=bye_msg.headers['cseq'][0])) | |
158 | ||
159 | if __name__ == '__main__': | |
160 | exec_test(test) | |
161 | exec_test(lambda q, bus, conn, stream: | |
162 | test(q, bus, conn, stream, 'foo@sip.bar.com')) |
0 | """ | |
1 | Test basic outgoing call handling, using CreateChannel and all three variations | |
2 | of RequestChannel. | |
3 | """ | |
4 | ||
5 | import dbus | |
6 | ||
7 | from sofiatest import exec_test | |
8 | from servicetest import ( | |
9 | make_channel_proxy, wrap_channel, | |
10 | EventPattern, call_async, | |
11 | assertEquals, assertContains, assertLength, | |
12 | ) | |
13 | import constants as cs | |
14 | from voip_test import VoipTestContext | |
15 | ||
16 | # There are various deprecated APIs for requesting calls, documented at | |
17 | # <http://telepathy.freedesktop.org/wiki/Requesting StreamedMedia channels>. | |
18 | # These are ordered from most recent to most deprecated. | |
19 | CREATE = 0 # CreateChannel({TargetHandleType: Contact, TargetHandle: h}); | |
20 | # RequestStreams() | |
21 | REQUEST_ANONYMOUS = 1 # RequestChannel(HandleTypeNone, 0); RequestStreams() | |
22 | REQUEST_ANONYMOUS_AND_ADD = 2 # RequestChannel(HandleTypeNone, 0); | |
23 | # AddMembers([h], ...); RequestStreams(h,...) | |
24 | REQUEST_NONYMOUS = 3 # RequestChannel(HandleTypeContact, h); | |
25 | # RequestStreams(h, ...) | |
26 | ||
27 | def create(q, bus, conn, sip_proxy, peer='foo@bar.com'): | |
28 | worker(q, bus, conn, sip_proxy, CREATE, peer) | |
29 | ||
30 | def request_anonymous(q, bus, conn, sip_proxy, peer='publish@foo.com'): | |
31 | worker(q, bus, conn, sip_proxy, REQUEST_ANONYMOUS, peer) | |
32 | ||
33 | def request_anonymous_and_add(q, bus, conn, sip_proxy, | |
34 | peer='publish-subscribe@foo.com/Res'): | |
35 | worker(q, bus, conn, sip_proxy, REQUEST_ANONYMOUS_AND_ADD, peer) | |
36 | ||
37 | def request_nonymous(q, bus, conn, sip_proxy, peer='subscribe@foo.com'): | |
38 | worker(q, bus, conn, sip_proxy, REQUEST_NONYMOUS, peer) | |
39 | ||
40 | def worker(q, bus, conn, sip_proxy, variant, peer): | |
41 | conn.Connect() | |
42 | q.expect('dbus-signal', signal='StatusChanged', args=[0, 1]) | |
43 | ||
44 | self_handle = conn.GetSelfHandle() | |
45 | context = VoipTestContext(q, conn, bus, sip_proxy, 'sip:testacc@127.0.0.1', peer) | |
46 | ||
47 | self_handle = conn.GetSelfHandle() | |
48 | remote_handle = conn.RequestHandles(1, [context.peer])[0] | |
49 | ||
50 | if variant == REQUEST_NONYMOUS: | |
51 | path = conn.RequestChannel(cs.CHANNEL_TYPE_STREAMED_MEDIA, | |
52 | cs.HT_CONTACT, remote_handle, True) | |
53 | elif variant == CREATE: | |
54 | path = conn.Requests.CreateChannel({ | |
55 | cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAMED_MEDIA, | |
56 | cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT, | |
57 | cs.TARGET_HANDLE: remote_handle, | |
58 | })[0] | |
59 | else: | |
60 | path = conn.RequestChannel(cs.CHANNEL_TYPE_STREAMED_MEDIA, | |
61 | cs.HT_NONE, 0, True) | |
62 | ||
63 | old_sig, new_sig = q.expect_many( | |
64 | EventPattern('dbus-signal', signal='NewChannel', | |
65 | predicate=lambda e: cs.CHANNEL_TYPE_CONTACT_LIST not in e.args), | |
66 | EventPattern('dbus-signal', signal='NewChannels', | |
67 | predicate=lambda e: | |
68 | cs.CHANNEL_TYPE_CONTACT_LIST not in e.args[0][0][1].values()), | |
69 | ) | |
70 | ||
71 | if variant == REQUEST_NONYMOUS or variant == CREATE: | |
72 | assertEquals( [path, cs.CHANNEL_TYPE_STREAMED_MEDIA, cs.HT_CONTACT, | |
73 | remote_handle, True], old_sig.args) | |
74 | else: | |
75 | assertEquals( [path, cs.CHANNEL_TYPE_STREAMED_MEDIA, cs.HT_NONE, 0, | |
76 | True], old_sig.args) | |
77 | ||
78 | assertLength(1, new_sig.args) | |
79 | assertLength(1, new_sig.args[0]) # one channel | |
80 | assertLength(2, new_sig.args[0][0]) # two struct members | |
81 | emitted_props = new_sig.args[0][0][1] | |
82 | ||
83 | assertEquals( | |
84 | cs.CHANNEL_TYPE_STREAMED_MEDIA, emitted_props[cs.CHANNEL_TYPE]) | |
85 | ||
86 | if variant == REQUEST_NONYMOUS or variant == CREATE: | |
87 | assertEquals(remote_handle, emitted_props[cs.TARGET_HANDLE]) | |
88 | assertEquals(cs.HT_CONTACT, emitted_props[cs.TARGET_HANDLE_TYPE]) | |
89 | assertEquals(context.peer_id, emitted_props[cs.TARGET_ID]) | |
90 | else: | |
91 | assertEquals(0, emitted_props[cs.TARGET_HANDLE]) | |
92 | assertEquals(cs.HT_NONE, emitted_props[cs.TARGET_HANDLE_TYPE]) | |
93 | assertEquals('', emitted_props[cs.TARGET_ID]) | |
94 | ||
95 | assertEquals(True, emitted_props[cs.REQUESTED]) | |
96 | assertEquals(self_handle, emitted_props[cs.INITIATOR_HANDLE]) | |
97 | assertEquals('sip:testacc@127.0.0.1', emitted_props[cs.INITIATOR_ID]) | |
98 | ||
99 | chan = wrap_channel(bus.get_object(conn.bus_name, path), 'StreamedMedia', | |
100 | ['MediaSignalling']) | |
101 | ||
102 | # Exercise basic Channel Properties | |
103 | channel_props = chan.Properties.GetAll(cs.CHANNEL) | |
104 | ||
105 | assertEquals(cs.CHANNEL_TYPE_STREAMED_MEDIA, | |
106 | channel_props.get('ChannelType')) | |
107 | ||
108 | if variant == REQUEST_NONYMOUS or variant == CREATE: | |
109 | assertEquals(remote_handle, channel_props['TargetHandle']) | |
110 | assertEquals(cs.HT_CONTACT, channel_props['TargetHandleType']) | |
111 | assertEquals(context.peer_id, channel_props['TargetID']) | |
112 | assertEquals((cs.HT_CONTACT, remote_handle), chan.GetHandle()) | |
113 | else: | |
114 | assertEquals(0, channel_props['TargetHandle']) | |
115 | assertEquals(cs.HT_NONE, channel_props['TargetHandleType']) | |
116 | assertEquals('', channel_props['TargetID']) | |
117 | assertEquals((cs.HT_NONE, 0), chan.GetHandle()) | |
118 | ||
119 | for interface in [ | |
120 | cs.CHANNEL_IFACE_GROUP, cs.CHANNEL_IFACE_MEDIA_SIGNALLING, | |
121 | cs.TP_AWKWARD_PROPERTIES, cs.CHANNEL_IFACE_HOLD]: | |
122 | assertContains(interface, channel_props['Interfaces']) | |
123 | ||
124 | assertEquals(True, channel_props['Requested']) | |
125 | assertEquals('sip:testacc@127.0.0.1', channel_props['InitiatorID']) | |
126 | assertEquals(conn.GetSelfHandle(), channel_props['InitiatorHandle']) | |
127 | ||
128 | # Exercise Group Properties | |
129 | group_props = chan.Properties.GetAll(cs.CHANNEL_IFACE_GROUP) | |
130 | ||
131 | assertEquals([self_handle], group_props['Members']) | |
132 | assertEquals([], group_props['LocalPendingMembers']) | |
133 | ||
134 | if variant == REQUEST_NONYMOUS: | |
135 | # In this variant, they're meant to be in RP even though we've sent | |
136 | # nothing | |
137 | assertEquals([remote_handle], group_props['RemotePendingMembers']) | |
138 | else: | |
139 | # For an anonymous channel, the peer isn't yet known; for a Create-d | |
140 | # channel, the peer only appears in RP when we actually send them the | |
141 | # session-initiate | |
142 | assertEquals([], group_props['RemotePendingMembers']) | |
143 | ||
144 | if variant == REQUEST_ANONYMOUS_AND_ADD: | |
145 | # but we should be allowed to add the peer. | |
146 | chan.Group.AddMembers([remote_handle], 'I love backwards compat') | |
147 | ||
148 | base_flags = cs.GF_PROPERTIES | cs.GF_CAN_REMOVE | cs.GF_CAN_RESCIND | |
149 | ||
150 | if variant in [REQUEST_ANONYMOUS_AND_ADD, REQUEST_ANONYMOUS, CREATE]: | |
151 | expected_flags = base_flags | cs.GF_CAN_ADD | |
152 | else: | |
153 | expected_flags = base_flags | |
154 | ||
155 | assertEquals(bin(expected_flags), bin(group_props['GroupFlags'])) | |
156 | assertEquals({}, group_props['HandleOwners']) | |
157 | ||
158 | assertEquals([], chan.StreamedMedia.ListStreams()) | |
159 | streams = chan.StreamedMedia.RequestStreams(remote_handle, | |
160 | [cs.MEDIA_STREAM_TYPE_AUDIO]) | |
161 | assertEquals(streams, chan.StreamedMedia.ListStreams()) | |
162 | assertLength(1, streams) | |
163 | ||
164 | # streams[0][0] is the stream identifier, which in principle we can't | |
165 | # make any assertion about (although in practice it's probably 1) | |
166 | ||
167 | assertEquals(( | |
168 | remote_handle, | |
169 | cs.MEDIA_STREAM_TYPE_AUDIO, | |
170 | # We haven't connected yet | |
171 | cs.MEDIA_STREAM_STATE_DISCONNECTED, | |
172 | # In Gabble, requested streams start off bidirectional | |
173 | cs.MEDIA_STREAM_DIRECTION_BIDIRECTIONAL, | |
174 | cs.MEDIA_STREAM_PENDING_REMOTE_SEND), | |
175 | streams[0][1:]) | |
176 | ||
177 | # S-E does state recovery to get the session handler, and calls Ready on it | |
178 | session_handlers = chan.MediaSignalling.GetSessionHandlers() | |
179 | sh_path, sh_type = session_handlers[0] | |
180 | ||
181 | assert sh_type == 'rtp' | |
182 | ||
183 | session_handler = make_channel_proxy(conn, sh_path, 'Media.SessionHandler') | |
184 | session_handler.Ready() | |
185 | ||
186 | e = q.expect('dbus-signal', signal='NewStreamHandler') | |
187 | ||
188 | stream_handler = make_channel_proxy(conn, e.args[0], 'Media.StreamHandler') | |
189 | ||
190 | stream_handler.NewNativeCandidate("fake", context.get_remote_transports_dbus()) | |
191 | stream_handler.NativeCandidatesPrepared() | |
192 | stream_handler.Ready(context.get_audio_codecs_dbus()) | |
193 | stream_handler.StreamState(cs.MEDIA_STREAM_STATE_CONNECTED) | |
194 | ||
195 | sh_props = stream_handler.GetAll( | |
196 | cs.STREAM_HANDLER, dbus_interface=dbus.PROPERTIES_IFACE) | |
197 | assertEquals('none', sh_props['NATTraversal']) | |
198 | assertEquals(True, sh_props['CreatedLocally']) | |
199 | ||
200 | if variant == CREATE: | |
201 | # When we actually send INVITE to the peer, they should pop up in remote | |
202 | # pending. | |
203 | invite_event, _ = q.expect_many( | |
204 | EventPattern('sip-invite'), | |
205 | EventPattern('dbus-signal', signal='MembersChanged', | |
206 | args=["", [], [], [], [remote_handle], self_handle, | |
207 | cs.GC_REASON_INVITED]), | |
208 | ) | |
209 | else: | |
210 | invite_event = q.expect('sip-invite') | |
211 | ||
212 | # Check the Group interface's properties again. Regardless of the call | |
213 | # requesting API in use, the state should be the same here: | |
214 | group_props = chan.Properties.GetAll(cs.CHANNEL_IFACE_GROUP) | |
215 | assertContains('HandleOwners', group_props) | |
216 | assertEquals([self_handle], group_props['Members']) | |
217 | assertEquals([], group_props['LocalPendingMembers']) | |
218 | assertEquals([remote_handle], group_props['RemotePendingMembers']) | |
219 | ||
220 | context.check_call_sdp(invite_event.sip_message.body) | |
221 | context.accept(invite_event.sip_message) | |
222 | ||
223 | ack_cseq = "%s ACK" % invite_event.cseq.split()[0] | |
224 | q.expect_many( | |
225 | EventPattern('sip-ack', cseq=ack_cseq), | |
226 | # Call accepted | |
227 | EventPattern('dbus-signal', signal='MembersChanged', | |
228 | args=['', [remote_handle], [], [], [], remote_handle, | |
229 | cs.GC_REASON_NONE]), | |
230 | ) | |
231 | ||
232 | # Time passes ... afterwards we close the chan | |
233 | ||
234 | chan.Group.RemoveMembers([self_handle], 'closed') | |
235 | ||
236 | ||
237 | mc_event, _, bye_event = q.expect_many( | |
238 | EventPattern('dbus-signal', signal='MembersChanged'), | |
239 | EventPattern('dbus-signal', signal='Close'), | |
240 | EventPattern('sip-bye', call_id=context.call_id), | |
241 | ) | |
242 | # Check that we're the actor | |
243 | assertEquals(self_handle, mc_event.args[5]) | |
244 | ||
245 | # For completeness, reply to the BYE. | |
246 | bye_response = sip_proxy.responseFromRequest(200, bye_event.sip_message) | |
247 | sip_proxy.deliverResponse(bye_response) | |
248 | ||
249 | def rccs(q, bus, conn, stream): | |
250 | """ | |
251 | Tests that the connection's RequestableChannelClasses for StreamedMedia are | |
252 | sane. | |
253 | """ | |
254 | conn.Connect() | |
255 | ||
256 | q.expect('dbus-signal', signal='StatusChanged', | |
257 | args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED]) | |
258 | ||
259 | rccs = conn.Properties.Get(cs.CONN_IFACE_REQUESTS, | |
260 | 'RequestableChannelClasses') | |
261 | ||
262 | # Test Channel.Type.StreamedMedia | |
263 | media_classes = [ rcc for rcc in rccs | |
264 | if rcc[0][cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_STREAMED_MEDIA ] | |
265 | ||
266 | assertLength(1, media_classes) | |
267 | ||
268 | fixed, allowed = media_classes[0] | |
269 | ||
270 | assertEquals(cs.HT_CONTACT, fixed[cs.TARGET_HANDLE_TYPE]) | |
271 | ||
272 | expected_allowed = [ | |
273 | cs.TARGET_ID, cs.TARGET_HANDLE, | |
274 | cs.INITIAL_VIDEO, cs.INITIAL_AUDIO | |
275 | ] | |
276 | ||
277 | allowed.sort() | |
278 | expected_allowed.sort() | |
279 | assertEquals(expected_allowed, allowed) | |
280 | ||
281 | if __name__ == '__main__': | |
282 | ||
283 | exec_test(rccs) | |
284 | exec_test(create) | |
285 | exec_test(request_anonymous) | |
286 | exec_test(request_anonymous_and_add) | |
287 | exec_test(request_nonymous) | |
288 | exec_test(lambda q, b, c, s: | |
289 | create(q, b, c, s, peer='foo@gw.bar.com')) | |
290 | exec_test(lambda q, b, c, s: | |
291 | request_anonymous(q, b, c, s, peer='foo@gw.bar.com')) | |
292 | exec_test(lambda q, b, c, s: | |
293 | request_anonymous_and_add(q, b, c, s, peer='foo@gw.bar.com')) | |
294 | exec_test(lambda q, b, c, s: | |
295 | request_nonymous(q, b, c, s, peer='foo@gw.bar.com')) |
0 | ||
1 | import dbus | |
2 | import uuid | |
3 | ||
4 | import twisted.protocols.sip | |
5 | ||
6 | from servicetest import assertContains | |
7 | ||
8 | class VoipTestContext(object): | |
9 | # Default audio codecs for the remote end | |
10 | audio_codecs = [ ('GSM', 3, 8000, {}), | |
11 | ('PCMA', 8, 8000, {}), | |
12 | ('PCMU', 0, 8000, {}) ] | |
13 | ||
14 | # Default video codecs for the remote end. I have no idea what's | |
15 | # a suitable value here... | |
16 | video_codecs = [ ('WTF', 42, 80000, {}) ] | |
17 | ||
18 | # Default candidates for the remote end | |
19 | remote_transports = [ | |
20 | ( "192.168.0.1", # host | |
21 | 666, # port | |
22 | 0, # protocol = TP_MEDIA_STREAM_BASE_PROTO_UDP | |
23 | "RTP", # protocol subtype | |
24 | "AVP", # profile | |
25 | 1.0, # preference | |
26 | 0, # transport type = TP_MEDIA_STREAM_TRANSPORT_TYPE_LOCAL, | |
27 | "username", | |
28 | "password" ) ] | |
29 | ||
30 | _mline_template = 'm=audio %(port)s %(subtype)s/%(profile)s %(codec_ids)s' | |
31 | _aline_template = 'a=rtpmap:%(codec_id)s %(name)s/%(rate)s' | |
32 | ||
33 | def __init__(self, q, conn, bus, sip_proxy, our_uri, peer): | |
34 | self.bus = bus | |
35 | self.conn = conn | |
36 | self.q = q | |
37 | self.our_uri = our_uri | |
38 | self.peer = peer | |
39 | self.peer_id = "sip:" + peer | |
40 | self.sip_proxy = sip_proxy | |
41 | self._cseq_id = 1 | |
42 | ||
43 | def dbusify_codecs(self, codecs): | |
44 | dbussed_codecs = [ (id, name, 0, rate, 0, params ) | |
45 | for (name, id, rate, params) in codecs ] | |
46 | return dbus.Array(dbussed_codecs, signature='(usuuua{ss})') | |
47 | ||
48 | def dbusify_codecs_with_params (self, codecs): | |
49 | return self.dbusify_codecs(codecs) | |
50 | ||
51 | def get_audio_codecs_dbus(self): | |
52 | return self.dbusify_codecs(self.audio_codecs) | |
53 | ||
54 | def get_video_codecs_dbus(self): | |
55 | return self.dbusify_codecs(self.video_codecs) | |
56 | ||
57 | def dbusify_call_codecs(self, codecs): | |
58 | dbussed_codecs = [ (id, name, rate, 0, params) | |
59 | for (name, id, rate, params) in codecs ] | |
60 | return dbus.Array(dbussed_codecs, signature='(usuua{ss})') | |
61 | ||
62 | def dbusify_call_codecs_with_params(self, codecs): | |
63 | return dbusify_call_codecs (self, codecs) | |
64 | ||
65 | def get_call_audio_codecs_dbus(self): | |
66 | return self.dbusify_call_codecs(self.audio_codecs) | |
67 | ||
68 | def get_call_video_codecs_dbus(self): | |
69 | return self.dbusify_call_codecs(self.video_codecs) | |
70 | ||
71 | ||
72 | def get_remote_transports_dbus(self): | |
73 | return dbus.Array([ | |
74 | (dbus.UInt32(1 + i), host, port, proto, subtype, | |
75 | profile, pref, transtype, user, pwd) | |
76 | for i, (host, port, proto, subtype, profile, | |
77 | pref, transtype, user, pwd) | |
78 | in enumerate(self.remote_transports) ], | |
79 | signature='(usuussduss)') | |
80 | ||
81 | def get_call_remote_transports_dbus(self): | |
82 | return dbus.Array([ | |
83 | (1 , host, port, | |
84 | { "Type": transtype, | |
85 | "Foundation": "", | |
86 | "Protocol": proto, | |
87 | "Priority": int((1+i) * 65536), | |
88 | "Username": user, | |
89 | "Password": pwd } | |
90 | ) for i, (host, port, proto, subtype, profile, | |
91 | pref, transtype, user, pwd) | |
92 | in enumerate(self.remote_transports) ], | |
93 | signature='(usqa{sv})') | |
94 | ||
95 | def get_call_sdp(self): | |
96 | (ip, port, protocol, subtype, profile, preference, | |
97 | transport, username, password) = self.remote_transports[0] | |
98 | ||
99 | codec_id_list = [] | |
100 | codec_list = [] | |
101 | for name, codec_id, rate, _misc in self.audio_codecs: | |
102 | codec_list.append('a=rtpmap:%(codec_id)s %(name)s/%(rate)s' % locals()) | |
103 | codec_id_list.append(str(codec_id)) | |
104 | codec_ids = ' '.join(codec_id_list) | |
105 | codecs = '\r\n'.join(codec_list) | |
106 | ||
107 | sdp_string = ('v=0\r\n' | |
108 | 'o=- 7047265765596858314 2813734028456100815 IN IP4 %(ip)s\r\n' | |
109 | 's=-\r\n' | |
110 | 't=0 0\r\n' | |
111 | 'm=audio %(port)s RTP/AVP 3 8 0\r\n' | |
112 | 'c=IN IP4 %(ip)s\r\n' | |
113 | '%(codecs)s\r\n') % locals() | |
114 | return sdp_string | |
115 | ||
116 | def check_call_sdp(self, sdp_string): | |
117 | codec_id_list = [] | |
118 | for name, codec_id, rate, _misc in self.audio_codecs: | |
119 | assertContains (self._aline_template % locals(), sdp_string) | |
120 | codec_id_list.append(str(codec_id)) | |
121 | codec_ids = ' '.join(codec_id_list) | |
122 | ||
123 | (ip, port, protocol, subtype, profile, preference, | |
124 | transport, username, password) = self.remote_transports[0] | |
125 | assert self._mline_template % locals() in sdp_string | |
126 | ||
127 | def send_message(self, message_type, body='', to_=None, from_=None, | |
128 | **additional_headers): | |
129 | url = twisted.protocols.sip.parseURL('sip:testacc@127.0.0.1') | |
130 | msg = twisted.protocols.sip.Request(message_type, url) | |
131 | if body: | |
132 | msg.body = body | |
133 | msg.addHeader('content-length', '%d' % len(msg.body)) | |
134 | msg.addHeader('from', from_ or '<%s>;tag=XYZ' % self.peer_id) | |
135 | msg.addHeader('to', to_ or '<sip:testacc@127.0.0.1>') | |
136 | self._cseq_id += 1 | |
137 | additional_headers.setdefault('cseq', '%d %s' % (self._cseq_id, message_type)) | |
138 | for key, vals in additional_headers.items(): | |
139 | if not isinstance(vals, list): | |
140 | vals = [vals] | |
141 | k = key.replace('_', '-') | |
142 | for v in vals: | |
143 | msg.addHeader(k, v) | |
144 | via = self.sip_proxy.getVia() | |
145 | via.branch = 'z9hG4bKXYZ' | |
146 | msg.addHeader('via', via.toString()) | |
147 | _expire, destination = self.sip_proxy.registry.users['testacc'] | |
148 | self.sip_proxy.sendMessage(destination, msg) | |
149 | return msg | |
150 | ||
151 | def accept(self, invite_message): | |
152 | self.call_id = invite_message.headers['call-id'][0] | |
153 | response = self.sip_proxy.responseFromRequest(200, invite_message) | |
154 | # Echo sofiasip's SDP back to it. It doesn't care. | |
155 | response.addHeader('content-type', 'application/sdp') | |
156 | response.body = invite_message.body | |
157 | response.addHeader('content-length', '%d' % len(response.body)) | |
158 | self.sip_proxy.deliverResponse(response) | |
159 | return response | |
160 | ||
161 | def ack(self, ok_message): | |
162 | cseq = '%s ACK' % ok_message.headers['cseq'][0].split()[0] | |
163 | self.send_message('ACK', call_id=self.call_id, cseq=cseq) | |
164 | ||
165 | def incoming_call(self): | |
166 | self.call_id = uuid.uuid4().hex | |
167 | body = self.get_call_sdp() | |
168 | return self.send_message('INVITE', body, content_type='application/sdp', | |
169 | supported='timer, 100rel', call_id=self.call_id) | |
170 | ||
171 | def incoming_call_from_self(self): | |
172 | self.call_id = uuid.uuid4().hex | |
173 | body = self.get_call_sdp() | |
174 | return self.send_message('INVITE', body, content_type='application/sdp', | |
175 | supported='timer, 100rel', call_id=self.call_id, | |
176 | from_='<sip:testacc@127.0.0.1>') | |
177 | ||
178 | def terminate(self): | |
179 | return self.send_message('BYE', call_id=self.call_id) |