/[drupal]/contributions/modules/xmpp/xmpp.module
ViewVC logotype

Contents of /contributions/modules/xmpp/xmpp.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.4 - (show annotations) (download) (as text)
Mon Aug 20 03:17:29 2007 UTC (2 years, 3 months ago) by mkhitrov
Branch: MAIN
CVS Tags: HEAD
Changes since 1.3: +435 -440 lines
File MIME type: text/x-php
Some minor tweaks and improvements.
1 <?php
2 /* $Id$ */
3
4 /**
5 * @file
6 * Extensible Messaging and Presence Protocol API.
7 *
8 * Allows Drupal components to send instant messages to users via the extensible
9 * messaging and presence protocol.
10 */
11
12 /**
13 * Implementation of hook_help().
14 */
15 function xmpp_help($section) {
16 switch ($section) {
17 case 'admin/help#xmpp':
18 return '<p>' . t('
19 The XMPP module provides other Drupal components with a way to
20 communicate over the extensible messaging and presence protocol (aka
21 Jabber). Once enabled and configured, other modules will be able to send
22 instant messages to site users.
23 ') . '</p>';
24 }
25 }
26
27 /**
28 * Implementation of hook_perm().
29 */
30 function xmpp_perm() {
31 return array('administer xmpp');
32 }
33
34 /**
35 * Implementation of hook_enable().
36 */
37 function xmpp_enable() {
38 $secret = sha1(uniqid(mt_rand(), true));
39 variable_set('xmpp_server_secret', $secret);
40 variable_set('xmpp_client_auth_passwd', $secret);
41 }
42
43 /**
44 * Implementation of hook_menu().
45 */
46 function xmpp_menu($may_cache) {
47 $items = array();
48
49 if ($may_cache) {
50 $items[] = array(
51 'path' => 'admin/settings/xmpp',
52 'title' => t('XMPP Settings'),
53 'description' => t('Configure XMPP Module.'),
54 'callback' => 'drupal_get_form',
55 'callback arguments' => array('xmpp_client_settings'),
56 'access' => user_access('administer xmpp')
57 );
58
59 $items[] = array(
60 'path' => 'admin/settings/xmpp/client',
61 'title' => t('Client'),
62 'type' => MENU_DEFAULT_LOCAL_TASK,
63 'access' => user_access('administer xmpp')
64 );
65
66 $items[] = array(
67 'path' => 'admin/settings/xmpp/server',
68 'title' => t('Server'),
69 'callback' => 'drupal_get_form',
70 'callback arguments' => array('xmpp_server_settings'),
71 'type' => MENU_LOCAL_TASK,
72 'access' => user_access('administer xmpp')
73 );
74 }
75 else {
76 $items[] = array(
77 'path' => 'xmpp/server',
78 'title' => 'XMPP Server',
79 'callback' => 'xmpp_server',
80 'type' => MENU_CALLBACK,
81 'access' => variable_get('xmpp_server_enabled', false)
82 );
83 }
84
85 return $items;
86 }
87
88 /**
89 * Implementation of hook_form_alter().
90 */
91 function xmpp_form_alter($form_id, &$form) {
92 if ($form_id == 'xmpp_client_settings')
93 $form['#submit']['xmpp_client_settings_test'] = array();
94 }
95
96 /**
97 * Client settings page.
98 */
99 function xmpp_client_settings() {
100 $form = array();
101 $fields = array();
102 $crypto_disabled = !extension_loaded('openssl');
103 $crypto_text = ($crypto_disabled ? ' (Requires OpenSSL extension)' : '');
104 $crypto = ($crypto_disabled ? 'none' : 'tls');
105 $jid_format = htmlspecialchars('<user>@<domain>[/<resource>]');
106
107 $sql = 'SELECT fid, title FROM {profile_fields} WHERE type = \'textfield\'';
108 $query = db_query($sql);
109
110 while ($record = db_fetch_array($query))
111 $fields[$record['fid']] = $record['title'];
112
113 $transport_methods = array(
114 'tcp' => t('External (TCP/IP)'),
115 'webtcp' => t('Built-in (WebTCP)')
116 );
117
118 $crypto_methods = array(
119 'none' => t('None'),
120 'tls' => t('TLS'),
121 'ssl' => t('SSL')
122 );
123
124 //
125 // Basic settings
126 //
127
128 $form['client'] = array(
129 '#type' => 'fieldset',
130 '#title' => t('Basic settings')
131 );
132
133 $form['client']['xmpp_client_auth_jid'] = array(
134 '#type' => 'textfield',
135 '#title' => t('Username'),
136 '#description' => t('JID to use for authentication ('.$jid_format.').'),
137 '#default_value' => variable_get('xmpp_client_auth_jid', ''),
138 '#required' => true
139 );
140
141 $form['client']['xmpp_client_auth_passwd'] = array(
142 '#type' => 'password',
143 '#title' => t('Password'),
144 '#description' => t('Password to use for authentication. Leave this '.
145 'field blank to keep the old password or when using '.
146 'the built-in server.')
147 );
148
149 $form['client']['xmpp_client_jid_field'] = array(
150 '#type' => 'select',
151 '#title' => t('User JID Field'),
152 '#description' => t('Profile field which is used to store user JIDs. '.
153 'You should create this if it doesn\'t already '.
154 'exist.'),
155 '#options' => $fields,
156 '#default_value' => variable_get('xmpp_client_jid_field', ''),
157 '#required' => true
158 );
159
160 //
161 // Server type
162 //
163
164 $form['server_type'] = array(
165 '#type' => 'fieldset',
166 '#title' => t('Server type'),
167 );
168
169 $form['server_type']['xmpp_client_transport'] = array(
170 '#type' => 'radios',
171 '#title' => t('Transport method'),
172 '#description' => t('Server type and transport method to be used.'),
173 '#options' => $transport_methods,
174 '#default_value' => variable_get('xmpp_client_transport', 'tcp'),
175 '#required' => true
176 );
177
178 //
179 // External (TCP/IP)
180 //
181
182 $form['external_tcp'] = array(
183 '#type' => 'fieldset',
184 '#title' => t('External (TCP/IP)'),
185 '#collapsible' => true,
186 '#collapsed' => true
187 );
188
189 $form['external_tcp']['xmpp_client_tcp_host'] = array(
190 '#type' => 'textfield',
191 '#title' => t('Host'),
192 '#description' => t('Hostname or IP of the external server. This can '.
193 'usually be determined automatically from the JID.'),
194 '#default_value' => variable_get('xmpp_client_tcp_host', '')
195 );
196
197 $form['external_tcp']['xmpp_client_tcp_port'] = array(
198 '#type' => 'textfield',
199 '#title' => t('Port'),
200 '#description' => t('Port on which to establish the connection. The '.
201 'default is 5222, 5223 if SSL is used.'),
202 '#default_value' => variable_get('xmpp_client_tcp_port', ''),
203 '#maxlength' => 5
204 );
205
206 $form['external_tcp']['xmpp_client_tcp_use_dns'] = array(
207 '#type' => 'checkbox',
208 '#title' => t('Use DNS'),
209 '#default_value' => variable_get('xmpp_client_tcp_use_dns', true),
210 '#description' => t('Enable DNS SRV look-ups.')
211 );
212
213 $form['external_tcp']['xmpp_client_tcp_crypto'] = array(
214 '#type' => 'radios',
215 '#title' => t('Encryption mechanism'. $crypto_text),
216 '#description' => t('Type of encryption to use (if available).'),
217 '#default_value' => variable_get('xmpp_client_tcp_crypto', $crypto),
218 '#options' => $crypto_methods,
219 '#disabled' => $crypto_disabled
220 );
221
222 //
223 // Built-in (WebTCP)
224 //
225
226 $form['builtin_webtcp'] = array(
227 '#type' => 'fieldset',
228 '#title' => t('Built-in (WebTCP)'),
229 '#collapsible' => true,
230 '#collapsed' => true
231 );
232
233 $form['builtin_webtcp']['xmpp_client_webtcp_url'] = array(
234 '#type' => 'textfield',
235 '#title' => t('URL'),
236 '#description' => t('Location of the WebTCP server. Usually this is '.
237 'http://[your_domain]/[path_to_drupal]/xmpp/server. '.
238 'Do not add a trailing slash.'),
239 '#default_value' => variable_get('xmpp_client_webtcp_url',
240 url('xmpp/server', null, null, true))
241 );
242
243 //
244 // Test configuration
245 //
246
247 $form['test'] = array(
248 '#type' => 'fieldset',
249 '#title' => t('Test configuration'),
250 );
251
252 $form['test']['xmpp_client_test_jid'] = array(
253 '#type' => 'textfield',
254 '#title' => t('Recipient'),
255 '#description' => t('Send a test IM to the specified JID.')
256 );
257
258 return system_settings_form($form);
259 }
260
261 /**
262 * Validate client settings form.
263 */
264 function xmpp_client_settings_validate($form_id, $values, $form) {
265
266 if (!$values['xmpp_client_auth_passwd']) {
267
268 if (!($passwd = variable_get('xmpp_client_auth_passwd', ''))) {
269 form_set_error('', t('Please enter the password.'));
270 return;
271 }
272
273 form_set_value($form['client']['xmpp_client_auth_passwd'], $passwd);
274 }
275
276 if (!xmpp_check_jid($values['xmpp_client_auth_jid'])) {
277 form_set_error('', t('Please enter a valid JID.'));
278 return;
279 }
280
281 if ($values['xmpp_client_test_jid']) {
282 if (!xmpp_check_jid($values['xmpp_client_test_jid'])) {
283 form_set_error('', t('Please enter a valid test JID.'));
284 return;
285 }
286 }
287 }
288
289 /**
290 * Submit client settings form.
291 */
292 function xmpp_client_settings_test($form_id, $form) {
293
294 variable_set('xmpp_client_configured', true);
295
296 if (!($test_jid = $form['xmpp_client_test_jid']))
297 return;
298
299 if (!xmpp_message($test_jid, 'Hello, this is a test IM from Drupal :)')) {
300 drupal_set_message('Error sending message: '. xmpp_last_error(), 'error');
301 return;
302 }
303
304 drupal_set_message('Test message sent.');
305 }
306
307 /**
308 * Server settings page.
309 */
310 function xmpp_server_settings() {
311 $form = array();
312
313 $form['server'] = array(
314 '#type' => 'fieldset',
315 '#title' => t('Server configuration'),
316 );
317
318 $form['server']['xmpp_server_enabled'] = array(
319 '#type' => 'checkbox',
320 '#title' => t('Enable server'),
321 '#description' => t('Turn the built-in server on or off.'),
322 '#default_value' => variable_get('xmpp_server_enabled', false)
323 );
324
325 $form['server']['xmpp_server_stream_from'] = array(
326 '#type' => 'textfield',
327 '#title' => t('Host'),
328 '#description' => t('Domain name hosted by this server.'),
329 '#default_value' => variable_get('xmpp_server_stream_from', ''),
330 '#required' => true
331 );
332
333 $form['server']['xmpp_server_secret'] = array(
334 '#type' => 'textfield',
335 '#title' => t('Secret'),
336 '#description' => t('Secret phrase needed to activate the server. This '.
337 'value needs to be set as the client\'s password '.
338 'in order for it to be able to access the server. '.
339 'By default, server is protected with a random sha1 '.
340 'hash string and you should only modify this field '.
341 'if you want other sites to use this server.'),
342 '#default_value' => variable_get('xmpp_server_secret', ''),
343 '#required' => true
344 );
345
346 $form['server']['xmpp_server_webtcp_port_start'] = array(
347 '#type' => 'textfield',
348 '#title' => t('Start port'),
349 '#description' => t('First port that can be used for incoming '.
350 'connections. Must be greater than 5269.'),
351 '#default_value' => variable_get('xmpp_server_webtcp_port_start', '48004'),
352 '#maxlength' => 5,
353 '#required' => true
354 );
355
356 $form['server']['xmpp_server_webtcp_port_end'] = array(
357 '#type' => 'textfield',
358 '#title' => t('End port'),
359 '#description' => t('Last port that can be used for incoming '.
360 'connections. Must be greater than the start port.'),
361 '#default_value' => variable_get('xmpp_server_webtcp_port_end', '48127'),
362 '#maxlength' => 5,
363 '#required' => true
364 );
365
366 return system_settings_form($form);
367 }
368
369 /**
370 * Server node, responds to requests for /xmpp/server.
371 */
372 function xmpp_server($secret = '') {
373
374 if (!is_string($secret) || $secret !== variable_get('xmpp_server_secret', 0))
375 return drupal_access_denied();
376
377 require_once dirname(__FILE__).'/lib/server.inc';
378
379 $conf = array(
380 'stream.from' => variable_get('xmpp_server_stream_from', ''),
381 'webtcp.port.start' => variable_get('xmpp_server_webtcp_port_start', ''),
382 'webtcp.port.end' => variable_get('xmpp_server_webtcp_port_end', '')
383 );
384
385 try {
386 $sess = XMPP_Server::instance()->listen($conf);
387
388 while ($sess->ready)
389 $sess->wait();
390 }
391 catch (Exception $ex) {
392 if (isset($sess))
393 $sess->handleException($ex);
394 }
395 }
396
397 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
398 // API
399 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
400
401 /**
402 * Get a connected XMPP_Session object.
403 */
404 function xmpp_get_session() {
405 static $sess = null;
406 static $first = true;
407
408 if ($first) {
409
410 $first = false;
411
412 if (!variable_get('xmpp_client_configured', false))
413 return null;
414
415 require_once dirname(__FILE__).'/lib/client.inc';
416
417 $conf = array(
418 'auth.jid' => variable_get('xmpp_client_auth_jid', ''),
419 'auth.passwd' => variable_get('xmpp_client_auth_passwd', ''),
420 'transport' => variable_get('xmpp_client_transport', '')
421 );
422
423 if ($conf['transport'] == 'tcp') {
424 if ($host = variable_get('xmpp_client_tcp_host', ''))
425 $conf['tcp.host'] = $host;
426
427 if ($port = variable_get('xmpp_client_tcp_port', ''))
428 $conf['tcp.port'] = $port;
429
430 $conf['tcp.use_dns'] = variable_get('xmpp_client_tcp_use_dns', true);
431 $crypto = variable_get('xmpp_client_tcp_crypto', 'none');
432
433 if ($crypto == 'none')
434 $conf['tcp.use_tls'] = false;
435
436 if ($crypto == 'ssl')
437 $conf['tcp.use_ssl'] = true;
438 }
439 else {
440 $conf['webtcp.url'] = variable_get('xmpp_client_webtcp_url', '');
441 $conf['webtcp.url'] .= '/'.variable_get('xmpp_client_auth_passwd', '');
442 }
443
444 try {
445 $sess = XMPP_Client::instance()->connect($conf);
446 $sess->Presence->set(1);
447 }
448 catch (Exception $ex) {
449 $sess = null;
450 xmpp_last_error($ex->getMessage());
451 }
452 }
453
454 return ($sess && $sess->ready ? $sess : null);
455 }
456
457 /**
458 * Map user id to jabber id.
459 */
460 function xmpp_get_jid($uid = null) {
461
462 static $jid_regex = '/^[^@]+@[^\/]+(?:\/.+)?$/';
463 $fid = variable_get('xmpp_client_jid_field', '');
464
465 if ($fid === '')
466 return (is_array($uid) ? array() : '');
467
468 if (is_null($uid)) {
469 global $user;
470 $uid = $user->uid;
471 }
472
473 $match = (is_array($uid) ? 'uid IN ('.implode(',', $uid).')' : 'uid='.$uid);
474 $result = array();
475 $sql = "SELECT uid, value FROM {profile_values} WHERE $match AND fid=%d";
476 $query = db_query($sql, $fid);
477
478 while ($record = db_fetch_array($query)) {
479 if (xmpp_check_jid($record['value']))
480 $result[$record['uid']] = $record['value'];
481 }
482
483 return (is_array($uid) ? $result : ($result ? current($result) : ''));
484 }
485
486 /**
487 * Send an instant message to the specified jid.
488 */
489 function xmpp_message($jid, $message) {
490
491 if (!xmpp_presence_subscribe($jid))
492 return false;
493
494 if (!($sess = xmpp_get_session()))
495 return false;
496
497 try {
498 $sess->IM->send($jid, $message);
499 return true;
500 }
501 catch (Exception $ex) {
502 $sess->handleException($ex);
503 xmpp_last_error($ex->getMessage());
504 return false;
505 }
506 }
507
508 /**
509 * Subscribe to the presence status of a user.
510 */
511 function xmpp_presence_subscribe($jid) {
512
513 if (!xmpp_check_jid($jid) || !($sess = xmpp_get_session()))
514 return false;
515
516 list($local) = explode('/', variable_get('xmpp_client_auth_jid', ''), 2);
517 list($remote) = explode('/', $jid, 2);
518
519 $sql = 'SELECT * FROM {xmpp_presence} WHERE remote=\'%s\' AND local=\'%s\'';
520 $query = db_query($sql, $remote, $local);
521
522 if (db_fetch_array($query))
523 return true;
524
525 try {
526 $sess->Presence->subscribe($remote);
527
528 $sql = 'INSERT INTO {xmpp_presence} VALUES (\'%s\', \'%s\')';
529 $query = db_query($sql, $remote, $local);
530
531 return true;
532 }
533 catch (Exception $ex) {
534 $sess->handleException($ex);
535 xmpp_last_error($ex->getMessage());
536 return false;
537 }
538 }
539
540 /**
541 * Do not send any outgoing stanzas until xmpp_end_buffer is called.
542 */
543 function xmpp_start_buffer() {
544
545 if (!($sess = xmpp_get_session()))
546 return false;
547
548 $sess->stream->autosend = false;
549 return true;
550 }
551
552 /**
553 * Send all buffered stanzas and return to normal mode of operation.
554 */
555 function xmpp_end_buffer() {
556
557 if (!($sess = xmpp_get_session()))
558 return false;
559
560 try {
561 $sess->stream->send();
562 return true;
563 }
564 catch (Exception $ex) {
565 $sess->handleException($ex);
566 xmpp_last_error($ex->getMessage());
567 return false;
568 }
569 }
570
571 /**
572 * Check basic JID syntax.
573 */
574 function xmpp_check_jid($jid) {
575 return preg_match('/^[^@]+@[^\/]+(?:\/.+)?$/', $jid);
576 }
577
578 /**
579 * Get the last XMPP error message.
580 */
581 function xmpp_last_error($set = null) {
582 static $error = '';
583 return ($set ? $error = t($set) : $error);
584 }

  ViewVC Help
Powered by ViewVC 1.1.2