Changeset 350
- Timestamp:
- 02/23/08 14:01:21 (16 years ago)
- Location:
- plugins/jabberNotifications
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
plugins/jabberNotifications/_define.php
r347 r350 4 4 * This is Jabber Notifications, a plugin for Dotclear 2 * 5 5 * * 6 * Copyright (c) 2007 6 * Copyright (c) 2007,2008 * 7 7 * Oleksandr Syenchuk, Olivier Tétard and contributors. * 8 8 * * … … 21 21 /* Description*/ "Jabber notifications for new comments", 22 22 /* Author */ "Oleksandr Syenchuk", 23 /* Version */ '2. 4-beta1',23 /* Version */ '2.5', 24 24 /* Permissions */ 'usage,contentadmin' 25 25 ); -
plugins/jabberNotifications/class.jabbernotifier.php
r348 r350 56 56 { 57 57 if (is_array($to)) { 58 foreach ($to as $v) { 58 foreach ($to as $v) 59 { 59 60 if (is_string($v) && trim($v)) { 60 61 $this->dest[] = $v; … … 98 99 if ($this->j->connect($timeout)) { 99 100 $this->j->execute($timeout); 100 if (!$this->done) { 101 $this->j->disconnect(); 102 if (!$this->done && $this->status == 'ok') { 101 103 $this->status = 'notDone'; 102 104 } … … 108 110 public function handleConnected() 109 111 { 110 if (!$this->j->login( $this->user,$this->pass)) {112 if (!$this->j->login()) { 111 113 $this->status = 'loginFailure'; 112 114 } -
plugins/jabberNotifications/lib/class_Jabber.php
r345 r350 26 26 class Jabber 27 27 { 28 public $use_msg_composing = true;29 public $use_msg_delivered = false;30 public $use_msg_displayed = false;31 public $use_msg_offline = false;32 33 public $_server_host = '';34 28 public $_server_ip = ''; 35 public $_server_port = 5222;36 29 public $_connect_timeout = 4; 37 public $_username = '';38 public $_password = '';39 public $_resource = '';40 30 41 31 public $_iq_version_name = 'Jabber Notifications'; … … 67 57 // event will be fired) 68 58 public $handle_services_internally = false; 69 70 // If true, the server software name and version will automatically be queried71 // and stored in $this->server_software and $this->server_version at login72 public $auto_server_identify = true;73 74 public $server_software = '';75 public $server_version = '';76 public $server_os = '';77 59 78 60 public $protocol_version = false; // set this to an XMPP protocol revision to include it in the <stream:stream> tag … … 82 64 private $jid; 83 65 private $password; 66 private $resource; 84 67 85 68 private $username; … … 87 70 private $con; 88 71 89 public function __construct($host,$port,$jid,$password,$con='') 90 { 91 $this->_unique_counter = 0; 72 public function __construct($host,$port,$jid,$password,$con='',$resource='blog') 73 { 92 74 $this->xml = new XMLParser(); 93 75 … … 95 77 $this->port = (int) $port; 96 78 $this->password = $password; 79 $this->resource = $resource; 97 80 98 81 $pos = strpos($jid,'@'); 99 82 if ($pos === false) { 100 $this->jid = $jid.'@'.$this->host ;83 $this->jid = $jid.'@'.$this->host.'/'.$resource; 101 84 $this->server = $host; 102 85 $this->username = $jid; 103 86 } 104 87 else { 105 $this->jid = $jid ;88 $this->jid = $jid.'/'.$resource; 106 89 $this->server = substr($jid,$pos+1); 107 90 $this->username = substr($jid,0,$pos); … … 154 137 } 155 138 156 private static function wait() 157 { 158 # Experimental sleeptime value 159 $sleeptime = 10000; 139 private static function wait($sleeptime=10000) 140 { 160 141 usleep($sleeptime); 161 142 } 162 143 163 144 // returns a unique ID to be sent with packets 164 function _unique_id($prefix) {165 $this->_unique_counter++;166 return $prefix. "_" . md5(time() . $_SERVER['REMOTE_ADDR'] . $this->_unique_counter);145 function _unique_id($prefix) 146 { 147 return $prefix.'_'.md5(uniqid(mt_rand())); 167 148 } 168 149 … … 188 169 // A "connected" event is also fired when the server responds to our <stream> packet. 189 170 // 190 // $server_host - Hostname of your Jabber server (portion after the "@" in your JID) 191 // $server_port - Port for your Jabber server 192 // $connect_timeout - Maximum number of seconds to wait for a connection 171 // $con_timeout - Maximum number of seconds to wait for a connection 193 172 // $alternate_ip - If $server_host does not resolve to your Jabber server's IP, 194 173 // specify the correct IP to connect to here … … 200 179 201 180 $this->_connection = new $connector(); 202 $this->_server_host = $this->host;203 $this->_server_port = $this->port;204 181 $this->_server_ip = $alternate_ip ? $alternate_ip : $this->host; 205 182 $this->_connect_timeout = (int) $con_timeout; … … 215 192 216 193 function _connect_socket() { 217 if ($this->_connection->socket_open($this->con.$this->_server_ip,$this-> _server_port,$this->_connect_timeout)) {194 if ($this->_connection->socket_open($this->con.$this->_server_ip,$this->port,$this->_connect_timeout)) { 218 195 $this->_send("<?xml version='1.0' encoding='UTF-8' ?" . ">\n"); 219 196 … … 231 208 function disconnect() 232 209 { 233 $this->_send( "</stream:stream>");210 $this->_send('</stream:stream>'); 234 211 235 212 return $this->_connection->socket_close(); 236 213 } 237 214 238 239 215 # Logs in to the server 240 function login($username,$password,$resource='blog') 241 { 242 if (!($username && $password)) { 243 return false; 244 } 245 246 // setup handler to automatically respond to the request 216 function login() 217 { 218 # setup handler to automatically respond to the request 247 219 $auth_id = $this->_unique_id('auth'); 248 220 $this->_set_iq_handler('_on_authentication_methods',$auth_id,'result'); 249 221 $this->_set_iq_handler('_on_authentication_result',$auth_id,'error'); 250 222 251 // prepare our shiny new JID 252 $this->_username = $this->username; 253 $this->_password = $password; 254 $this->_resource = $resource; 255 $this->jid = $this->_username.'@'.$this->_server_host.'/'.$this->_resource; 256 257 // request available authentication methods 258 $payload = '<username>'.$this->_username.'</username>'; 259 $packet = $this->_send_iq(NULL,'get',$auth_id,'jabber:iq:auth',$payload); 223 # request available authentication methods 224 $payload = '<username>'.$this->username.'</username>'; 225 $packet = $this->_send_iq(null,'get',$auth_id,'jabber:iq:auth',$payload); 260 226 261 227 return true; … … 282 248 $thread = $this->xmlentities($thread); 283 249 284 $xml = "<message to='".$to."' type='".$type."' id='".$id."'>\n";250 $xml = '<message to="'.$to.'" type="'.$type.'" id="'.$id.'">'; 285 251 286 252 if ($subject) $xml .= "<subject>".$subject."</subject>\n"; … … 322 288 if (!empty($packet['iq'])) { 323 289 $this->_handle_iq($packet); 324 }325 elseif (!empty($packet['message'])) {326 $this->_handle_message($packet);327 }328 elseif (!empty($packet['presence'])) {329 $this->_handle_presence($packet);330 290 } 331 291 elseif (!empty($packet['stream:stream'])) { … … 423 383 } 424 384 425 function varset($v)426 {427 return is_string($v) ? strlen($v)>0 : !empty($v);428 }429 430 // handle Message packets431 function _handle_message(&$packet) {432 // events that we recognize433 $events = array("composing","offine","delivered","displayed");434 435 // grab the message details436 $type = $packet['message']['@']['type'];437 if (!$type) $type = "chat";438 439 $from = $packet['message']['@']['from'];440 $to = $packet['message']['@']['to'];441 $id = $packet['message']['@']['id'];442 443 list($f_username,$f_domain,$f_resource) = $this->_split_jid($from);444 $from_jid = ($f_username?"{$f_username}@":"").$f_domain;445 446 $body = $packet['message']['#']['body'][0]['#'];447 $subject = $packet['message']['#']['subject'][0]['#'];448 $thread = $packet['message']['#']['thread'][0]['#'];449 450 // handle extended message info (to a certain extent, anyway)...451 // if any of the tags in $events are passed under an x element in the452 // jabber:x:event namespace, $extended[tagname] is set to TRUE453 $extended = false;454 $extended_id = NULL;455 $x = $packet['message']['#']['x'];456 457 if (is_array($x)) {458 foreach ($x as $key=>$element) {459 if ($element['@']['xmlns']=="jabber:x:event") {460 foreach ($element['#'] as $tag=>$element_content) {461 if (in_array($tag,$events)) {462 $extended[$tag] = true;463 }464 if ($tag=="id") {465 $extended_id = is_array($element_content)466 ? $element_content['0']['#'] : null;467 if (!$extended) $extended = array();468 }469 }470 }471 }472 }473 474 // if a message contains an x tag in the jabber:x:event namespace,475 // and doesn't contain a body or subject, then it's an event notification476 if (!$this->varset($body) && !$this->varset($subject) && is_array($extended)) {477 478 // is this a composing event (which needs special handling)?479 if ($extended['composing']) {480 $this->_call_handler("msgevent_composing_start",$from);481 $this->roster[$from_jid]["composing"] = true;482 } else {483 if ($this->roster[$from_jid]["composing"]) {484 $this->_call_handler("msgevent_composing_stop",$from);485 $this->roster[$from_jid]["composing"] = false;486 }487 }488 489 foreach ($extended as $event=>$value) {490 $this->_call_handler("msgevent_$event",$from);491 }492 493 // don't process the rest of the message event, as it's not really a message494 return;495 }496 497 498 // process the message499 switch($type) {500 case "error":501 $this->_handle_error(&$packet);502 break;503 case "groupchat":504 $this->_call_handler("message_groupchat",$packet);505 break;506 case "headline":507 $this->_call_handler("message_headline",$from,$to,$body,$subject,$x,$packet);508 break;509 case "chat":510 case "normal":511 default:512 if ($this->roster[$from_jid]["composing"]) $this->roster[$from_jid]["composing"] = false;513 if (($type!="chat") && ($type!="normal")) $type = "normal";514 $this->_call_handler("message_$type",$from,$to,$body,$subject,$thread,$id,$extended,$packet);515 break;516 517 }518 }519 520 // handle Presence packets521 function _handle_presence(&$packet) {522 $type = $packet['presence']['@']['type'];523 if (!$type) $type = "available";524 525 $from = $packet['presence']['@']['from'];526 527 list($f_username,$f_domain,$f_resource) = $this->_split_jid($from);528 $from_jid = ($f_username?"{$f_username}@":"").$f_domain;529 530 $is_service = (!strlen($f_username));531 532 $exists = ($is_service && $this->handle_services_internally) ? isset($this->services[$from_jid]) : isset($this->roster[$from_jid]);533 534 $nothing = false;535 $rosteritem = &$nothing;536 537 if ($exists) {538 if ($is_service && $this->handle_services_internally) {539 $use_services_array = true;540 $rosteritem = &$this->services[$from_jid];541 } else {542 $use_services_array = false;543 $rosteritem = &$this->roster[$from_jid];544 }545 } else {546 // Ignore roster updates for JIDs not in our roster, except547 // for subscription requests...548 549 if ($type=="available") {550 // ... but make note of the presence of non-roster items here, in case551 // the roster item is sent AFTER the presence packet... then we can apply the552 // presence when the roster item is received553 $show = $this->_show($packet['presence']['#']['show'][0]['#']);554 $this->presence_cache[$from_jid] = array(555 "status"=>$packet['presence']['#']['status'][0]['#'],556 "show"=>$show ? $show : "on"557 );558 559 return;560 }561 562 if ($type!="subscribe") {563 return;564 }565 }566 $call_update = false;567 568 switch($type) {569 case "error":570 $this->_handle_error(&$packet);571 break;572 case "probe":573 $this->_call_handler('probe',$packet);574 break;575 case "subscribe":576 // note: $rosteritem is not set here577 $this->_call_handler('subscribe',$packet);578 break;579 case "subscribed":580 $this->_call_handler('subscribed',$packet);581 break;582 case "unsubscribe":583 $this->_call_handler('unsubscribe',$packet);584 break;585 case "unsubscribed":586 $this->_call_handler('unsubscribed',$packet);587 break;588 case "unavailable":589 $rosteritem["show"] = "off";590 $call_update = true;591 break;592 case "available":593 $rosteritem["status"] = $packet['presence']['#']['status'][0]['#'];594 $show = $this->_show($packet['presence']['#']['show'][0]['#']);595 $rosteritem["show"] = $show ? $show : "on"; // away, chat, xa, dnd, or "" = online596 597 $call_update = true;598 break;599 }600 if ($call_update) {601 if ($use_services_array) {602 $this->_call_handler("serviceupdate",$from,false);603 } else {604 $this->_call_handler("rosterupdate",$from,false);605 }606 }607 }608 385 609 386 // handle Stream packets … … 638 415 $auth_id = $packet['iq']['@']['id']; 639 416 640 //*641 417 if (isset($packet['iq']['#']['query'][0]['#']['digest'])) { 642 418 $this->_sendauth_digest($auth_id); … … 645 421 $this->_sendauth_plaintext($auth_id); 646 422 } 647 648 //*/649 //$this->_sendauth_digest($auth_id);650 //$this->_sendauth_plaintext($auth_id);651 423 652 424 $this->_set_iq_handler("_on_authentication_result",$auth_id); … … 659 431 660 432 if ($result_type=="result") { 661 if ($this->auto_server_identify) $this->request_version($this->_server_host);662 663 433 $this->_call_handler("authenticated"); 664 434 $this->_authenticated = true; … … 666 436 $this->_handle_iq_error(&$packet,"authfailure"); 667 437 } 668 }669 670 // receives the results of a service browse query671 function _on_browse_result(&$packet) {672 $packet_type = $packet['iq']['@']['type'];673 674 // did we get a result? if so, process it, and remember the service list675 if ($packet_type=="result") {676 677 $this->services = array();678 679 if ($packet['iq']['#']['service']) {680 // Jabberd uses the 'service' element681 $servicekey = $itemkey = 'service';682 } elseif ($packet['iq']['#']['item']) {683 // Older versions of Merak use 'item'684 $servicekey = $itemkey = 'item';685 } elseif ($packet['iq']['#']['query']) {686 // Newer versions of Merak use 'query'687 $servicekey = 'query';688 $itemkey = 'item';689 } else {690 // try to figure out what to use691 $k = array_keys($packet['iq']['#']);692 $servicekey = $k[0];693 if (!$servicekey) return;694 }695 // if the item key is incorrect, try to figure that out as well696 if ($packet['iq']['#'][$servicekey] && !$packet['iq']['#'][$servicekey][0]['#'][$itemkey]) {697 $k = array_keys($packet['iq']['#'][$servicekey][0]['#']);698 $itemkey = $k[0];699 }700 701 $number_of_services = count($packet['iq']['#'][$servicekey][0]['#'][$itemkey]);702 703 $services_updated = false;704 for ($a = 0; $a < $number_of_services; $a++)705 {706 $svc = &$packet['iq']['#'][$servicekey][0]['#'][$itemkey][$a];707 708 $jid = strtolower($svc['@']['jid']);709 $is_new = !isset($this->services[$jid]);710 $this->services[$jid] = array(711 "type" => strtolower($svc['@']['type']),712 "status" => "Offline",713 "show" => "off",714 "name" => $svc['@']['name']715 );716 $number_of_namespaces = count($packet['iq']['#'][$servicekey][0]['#'][$itemkey][$a]['#']['ns']);717 for ($b = 0; $b < $number_of_namespaces; $b++) {718 $this->services[$jid]['namespaces'][$b] = $packet['iq']['#'][$servicekey][0]['#'][$itemkey][$a]['#']['ns'][$b]['#'];719 }720 721 if ($this->service_single_update) {722 $services_updated = true;723 } else {724 $this->_call_handler("serviceupdate",$jid,$is_new);725 }726 }727 728 if ($this->service_single_update && $services_updated) {729 $this->_call_handler("serviceupdate",NULL,$is_new);730 }731 732 // choke on error733 } elseif ($packet_type=="error") {734 $this->_handle_iq_error($packet);735 736 // confusion sets in737 }738 }739 740 // request software version from a JabberID741 function request_version($jid) {742 // setup handler to automatically respond to the request (it would anyway,743 // because of how we handle version packets, but... hey, why not be thorough)744 $ver_id = $this->_unique_id("ver");745 $this->_set_iq_handler("_handle_version_packet",$ver_id,"result");746 747 return $this->_send_iq($jid, 'get', $ver_id, "jabber:iq:version");748 438 } 749 439 … … 754 444 $packetid = $packet['iq']['@']['id']; 755 445 756 if ($packet_type=="result") { 757 // did we get a result? if so, process it, and update the contact's version information 758 $jid = $this->_bare_jid($from); 759 760 $version = &$packet['iq']['#']['query'][0]['#']; 761 if ($jid==$this->_server_host) { 762 //$this->server_software = $version['name'][0]['#']; 763 //$this->server_version = $version['version'][0]['#']; 764 //$this->server_os = $version['os'][0]['#']; 765 766 $this->is_merak = strtolower(substr($this->server_software,0,5))=="merak"; 767 } elseif ($this->roster[$jid]) { 768 $this->roster[$jid]["version"] = $version; 769 } 770 771 $this->_call_handler("rosterupdate",$jid,false); 772 773 } elseif ($packet_type=="get") { 446 if ($packet_type=="get") { 774 447 // did we get an inquiry? if so, send our version info 775 448 $payload = "<name>{$this->_iq_version_name}</name><version>{$this->_iq_version_version}</version>"; … … 789 462 $packetid = $packet['iq']['@']['id']; 790 463 791 if ($packet_type=="result") { 792 // did we get a result? if so, process it, and update the contact's time information 793 $jid = $this->_bare_jid($from); 794 795 $timeinfo = &$packet['iq']['#']['query'][0]['#']; 796 $this->roster[$jid]["time"] = $timeinfo; 797 798 $this->_call_handler("rosterupdate",$jid,false); 799 } elseif ($packet_type=="get") { 464 if ($packet_type=="get") { 800 465 // did we get an inquiry? if so, send our time info 801 466 $utc = gmdate('Ymd\TH:i:s'); … … 810 475 811 476 return true; 812 }813 814 815 function _on_private_data(&$packet) {816 $packet_type = $packet['iq']['@']['type'];817 if ($packet_type == 'result') {818 819 $rootnode = $packet['iq']['#']['query'][0]['#'];820 unset($rootnode[0]);821 $rootnode = array_shift($rootnode);822 $data = $rootnode[0];823 $namespace = $data['@']['xmlns'];824 $rawvalues = $data['#'];825 826 $values = array();827 if (is_array($rawvalues)) {828 foreach ($rawvalues as $k=>$v) {829 $values[$k] = $v[0]['#'];830 }831 }832 833 $this->_call_handler("privatedata",$packet['iq']['@']['id'],$namespace,$values);834 835 } elseif ($packet_type == 'error' && isset($packet['iq']['#']['error'][0]['#'])) {836 $this->_handle_iq_error(&$packet,"privatedatafailure");837 } else {838 $this->_call_handler("privatedatafailure",-2,"Unrecognized response from server");839 }840 477 } 841 478 … … 871 508 872 509 873 874 510 // ==== Authentication Methods =========================================================== 875 511 876 function _sendauth_digest($auth_id) { 877 878 $payload = "<username>{$this->_username}</username> 879 <resource>{$this->_resource}</resource> 880 <digest>" . sha1($this->_stream_id . $this->_password) . "</digest>"; 881 882 $this->_send_iq(NULL, 'set', $auth_id, "jabber:iq:auth", $payload); 883 } 884 885 function _sendauth_plaintext($auth_id) { 886 887 $payload = "<username>{$this->_username}</username> 888 <password>{$this->_password}</password> 889 <resource>{$this->_resource}</resource>"; 890 891 $this->_send_iq(NULL, 'set', $auth_id, "jabber:iq:auth", $payload); 512 function _sendauth_digest($auth_id) 513 { 514 $payload = 515 '<username>'.$this->username.'</username>'. 516 '<resource>'.$this->resource.'</resource>'. 517 '<digest>'.sha1($this->_stream_id.$this->password).'</digest>'; 518 519 $this->_send_iq(null,'set',$auth_id,'jabber:iq:auth',$payload); 520 } 521 522 function _sendauth_plaintext($auth_id) 523 { 524 $payload = 525 '<username>'.$this->username.'</username>'. 526 '<resource>'.$this->resource.'</resource>'. 527 '<password>'.$this->password.'</password>'; 528 529 $this->_send_iq(null,'set',$auth_id,'jabber:iq:auth',$payload); 892 530 } 893 531 894 532 895 // ==== Helper Methods ===================================================================896 897 function _show($show) {898 // off is not valid, but is used internally899 $valid_shows = array("","away","chat","dnd","xa","off");900 if (!in_array($show,$valid_shows)) $show = "";901 902 return $show;903 }904 905 function standardize_transport($transport,$force=true) {906 $transports = array("msn","aim","yim","icq","jab");907 if (!in_array($transport,$transports)) {908 if ($transport=="aol") {909 $transport = "aim";910 } elseif ($transport=="yahoo") {911 $transport = "yim";912 } else {913 if ($force) $transport = "jab";914 }915 }916 return $transport;917 }918 919 function get_transport($domain) {920 $transport = $this->services[$domain]["type"];921 return $this->standardize_transport($transport);922 }923 924 925 926 927 928 533 // ==== Packet Handling & Connection Methods ============================================= 929 534 930 535 // generates and transmits an IQ packet 931 function _send_iq($to = NULL, $type = 'get', $id = NULL, $xmlns = NULL, $payload = NULL, $from = NULL) { 536 function _send_iq($to=null,$type='get',$id=null,$xmlns=null,$payload=null,$from=null) 537 { 932 538 if (!preg_match("/^(get|set|result|error)$/", $type)) { 933 unset($type);934 935 539 return false; 936 937 } elseif ($id && $xmlns) { 938 $xml = "<iq type='$type' id='$id'"; 939 $xml .= ($to) ? " to='$to'" : ''; 940 $xml .= ($from) ? " from='$from'" : ''; 941 $xml .= "> 942 <query xmlns='$xmlns'> 943 $payload 944 </query> 945 </iq>"; 946 540 } 541 elseif ($id && $xmlns) { 542 $xml = 543 '<iq type="'.$type.'" id="'.$id.'"'.($to ? ' to="'.$to.'"' : '').($from ? ' from="'.$from.'"' : '').'>'. 544 ' <query xmlns="'.$xmlns.'">'.$payload.'</query>'. 545 '</iq>'; 546 947 547 return $this->_send($xml); 948 548 } … … 950 550 return false; 951 551 } 952 } 953 954 955 // writes XML data to the socket; trims and UTF8 encodes $xml before 956 // sending unless $pristine is true 957 function _send($xml,$pristine = false) { 958 // need UTF8 encoding to prevent character coding issues when 959 // users enter international characters 960 /* 961 if (!$pristine) { 962 $xml = trim(utf8_encode($xml)); 963 if (!$xml) return false; 964 } 965 */ 966 if(strlen($xml)==0) return true; 967 968 $res = $this->_connection->socket_write($xml); 969 970 return $res; 971 } 972 973 552 } 553 554 // writes XML data to the socket 555 function _send($xml) 556 { 557 if (empty($xml)) { 558 return true; 559 } 560 561 return $this->_connection->socket_write($xml); 562 } 974 563 975 564 function _receive() { -
plugins/jabberNotifications/locales/fr/main.po
r346 r350 195 195 msgstr "Connexion sécurisée :" 196 196 197 msgid "None" 198 msgstr "Aucune" -
plugins/jabberNotifications/test.php
r343 r350 9 9 $host = 'host'; 10 10 $port = 5222; 11 $con = ' ssl://'; # or '' or 'tls://'11 $con = ''; # or 'ssl://' or 'tls://' 12 12 $user = 'user@server'; 13 13 $pass = 'pass'; … … 64 64 public function handleConnected() 65 65 { 66 $this->j->login( $this->user,$this->pass);66 $this->j->login(); 67 67 echo "[I] Logged in\n"; 68 68 }
Note: See TracChangeset
for help on using the changeset viewer.