70_Jabber.pm 57 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440
  1. ##############################################################################
  2. # $Id: 70_Jabber.pm 12904 2016-12-29 12:44:32Z BioS $
  3. #
  4. # 70_Jabber.pm
  5. # An FHEM Perl module for connecting to an Jabber XMPP Server and
  6. # send/recieve messages.
  7. # Thanks to Predictor who had the initial idea for such a module.
  8. #
  9. # Copyright by BioS
  10. #
  11. # This file is part of fhem.
  12. #
  13. # Fhem is free software: you can redistribute it and/or modify
  14. # it under the terms of the GNU General Public License as published by
  15. # the Free Software Foundation, either version 2 of the License, or
  16. # (at your option) any later version.
  17. #
  18. # Fhem is distributed in the hope that it will be useful,
  19. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  20. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  21. # GNU General Public License for more details.
  22. #
  23. # You should have received a copy of the GNU General Public License
  24. # along with fhem. If not, see <http://www.gnu.org/licenses/>.
  25. #
  26. # Version: 1.7 - 2016-12-29
  27. #
  28. # Changelog:
  29. # v1.7 2016-12-29 Added possibility to change componentname via attr JabberDomain (thx Turbokid)
  30. # v1.6 2016-07-10 Fix log message if otr message is empty (thx spikeh1)
  31. # v1.5 2015-09-17 Added OTR (Off the Record) end to end encryption
  32. # Added MUC (Multi-User-Channel) joining and handling
  33. # v1.4 2015-08-27 Fixed broken callback registration in Net::XMPP >= 1.04
  34. # v1.3 2015-01-10 Fixed DNS SRV resolving and resulting wrong to: address
  35. # v1.2 2015-01-09 hardening XML::Stream Process() call and fix of ssl_verify
  36. # v1.1 2014-07-28 Added UTF8 encoding / decoding to Messages
  37. # v1.0 2014-04-10 Stable Release - Housekeeping & Add to SVN
  38. # v0.3 2014-03-19 Fixed SetPresence() & Added extensive debugging capabilities by setting $debug to 1
  39. # v0.2 2014-01-28 Added SSL option in addition to TLS
  40. # v0.1 2014-01-18 Initial Release
  41. ##############################################################################
  42. # You will need the following perl Module and all it's depencies for this to work:
  43. # Net::Jabber
  44. # For using the SSL features and to connect securly to a Jabber server you also need this perl Module:
  45. # Net::SSLeay
  46. #
  47. # For using OTR you need to compile Crypt::OTR from CPAN on your own
  48. #
  49. # The recommended debian packages to be installed are these:
  50. # libnet-jabber-perl libnet-xmpp-perl libxml-stream-perl libdigest-sha1-perl libauthen-sasl-perl libnet-ssleay-perl
  51. #
  52. # Have Phun!
  53. #
  54. package main;
  55. use strict;
  56. use warnings;
  57. use utf8;
  58. use Time::HiRes qw(gettimeofday);
  59. use Net::Jabber;
  60. use base qw( Net::XMPP::Namespaces );
  61. use Blocking;
  62. sub Jabber_Set($@);
  63. sub Jabber_Define($$);
  64. sub Jabber_UnDef($$);
  65. sub Jabber_PollMessages($);
  66. sub Jabber_CheckConnection($);
  67. # If you want extended logging and debugging infomations
  68. # in fhem.log please set the following value to 1
  69. my $debug = 0;
  70. my %sets = (
  71. "msg" => 1,
  72. "msgmuc" => 1,
  73. "msgotr" => 1,
  74. "subscribe" => 1
  75. );
  76. ###################################
  77. sub
  78. Jabber_Initialize($)
  79. {
  80. my ($hash) = @_;
  81. $hash->{SetFn} = "Jabber_Set";
  82. $hash->{DefFn} = "Jabber_Define";
  83. $hash->{UndefFn} = "Jabber_UnDef";
  84. $hash->{AttrFn} = "Jabber_Attr";
  85. $hash->{AttrList} = "dummy:1,0 loglevel:0,1,2,3,4,5 OnlineStatus:available,unavailable PollTimer RecvWhitelist ResourceName MucJoin MucRecvWhitelist OTREnable OTRSharedSecret JabberDomain ".$readingFnAttributes;
  86. }
  87. ###################################
  88. sub Jabber_Set($@)
  89. {
  90. my ($hash, $name, $cmd, @args) = @_;
  91. if (!defined($sets{$cmd}))
  92. {
  93. return "Unknown argument " . $cmd . ", choose one of " . join(" ", sort keys %sets);
  94. }
  95. if ($cmd eq 'msg')
  96. {
  97. return Jabber_Set_Message($hash, @args);
  98. }
  99. if ($cmd eq 'msgmuc')
  100. {
  101. return Jabber_Set_MUCMessage($hash, @args);
  102. }
  103. if ($cmd eq 'msgotr')
  104. {
  105. return Jabber_Set_OTRMessage($hash, @args);
  106. }
  107. if ($cmd eq 'subscribe')
  108. {
  109. return Jabber_Subcribe_To($hash, @args);
  110. }
  111. }
  112. ###################################
  113. # Set's
  114. ###################################
  115. sub Jabber_Set_Message($@)
  116. {
  117. my ($hash,$dst,@tmpMsg) = @_;
  118. my $message = join(" ", @tmpMsg);
  119. utf8::decode($message);
  120. if (Jabber_CheckConnection($hash)) {
  121. $hash->{JabberDevice}->MessageSend(to=>$dst,
  122. body=>$message,
  123. type=>"chat",
  124. priority=>10);
  125. }
  126. }
  127. ###################################
  128. sub Jabber_Set_MUCMessage($@)
  129. {
  130. my ($hash,$dst,@tmpMsg) = @_;
  131. my $message = join(" ", @tmpMsg);
  132. utf8::decode($message);
  133. if (Jabber_CheckConnection($hash)) {
  134. #convert the groupchat id to a short id else this would be a private message which is not allowed via "groupchat" type
  135. my $JID = new Net::Jabber::JID($dst);
  136. my $senderShort = $JID->GetJID("base");
  137. $hash->{JabberDevice}->MessageSend(to=>$senderShort,
  138. body=>$message,
  139. type=>"groupchat",
  140. priority=>10);
  141. }
  142. }
  143. ###################################
  144. sub Jabber_Set_OTRMessage($@)
  145. {
  146. my ($hash,$dst,@tmpMsg) = @_;
  147. my $message = join(" ", @tmpMsg);
  148. utf8::decode($message);
  149. if (Jabber_CheckConnection($hash)) {
  150. if ($hash->{helper}{otractive}) {
  151. my $JID = new Net::Jabber::JID($dst);
  152. if (defined($hash->{helper}{otrJIDs}{$JID->GetJID("full")}) && defined($hash->{helper}{otrJIDs}{$JID->GetJID("full")}{verified}) ) {
  153. #send a encrypted message as we have an connection
  154. if (my $ciphertext = $hash->{OTR}->encrypt($JID->GetJID("full"), $message)) {
  155. Log 0, "$hash->{NAME} Secure sending to ".$JID->GetJID("full") if $debug;
  156. Jabber_Set_Message($hash,$dst,$ciphertext);
  157. } else {
  158. Log 0, "$hash->{NAME} Your message was not sent - no encrypted conversation is established" if $debug;
  159. }
  160. } else {
  161. #establish a secure connection and send the message then.
  162. Log 0, "$hash->{NAME} No secure connection to ".$JID->GetJID("full")." - establishing and sending message later..." if $debug;
  163. #send it later
  164. push @{ $hash->{helper}{otrJIDs}{$JID->GetJID("full")}{waitingMsgs} }, {"jid" => $JID->GetJID("full"), "msg" => $message} ;
  165. #establish...
  166. $hash->{OTR}->establish($JID->GetJID("full"));
  167. }
  168. } else {
  169. return "OTR not activated. Activate by using 'attr $hash->{NAME} OTREnable 1'";
  170. }
  171. }
  172. }
  173. ###################################
  174. sub Jabber_Subcribe_To($@)
  175. {
  176. my ($hash,$dst) = @_;
  177. if (Jabber_CheckConnection($hash)) {
  178. #respond with authorization so they can see our online state
  179. $hash->{JabberDevice}->Subscription(type=>"subscribed",
  180. to=>$dst);
  181. #ask for authorization also so we can also see their online state (for future)
  182. $hash->{JabberDevice}->Subscription(type=>"subscribe",
  183. to=>$dst);
  184. }
  185. }
  186. ###################################
  187. sub
  188. Jabber_Define($$)
  189. {
  190. my ($hash, $def) = @_;
  191. my $name = $hash->{NAME};
  192. my @args = split("[ \t]+", $def);
  193. if (int(@args) < 8)
  194. {
  195. return "Invalid number of arguments: define <name> Jabber <server> <port> <username> <password> <tls> <ssl>";
  196. }
  197. my ($tmp1,$tmp2,$server, $port, $username, $password, $tls, $ssl) = @args;
  198. $hash->{STATE} = 'Initialized';
  199. #defaults:
  200. $attr{$name}{PollTimer}=2;
  201. $attr{$name}{ResourceName}='FHEM';
  202. $attr{$name}{RecvWhitelist}='.*';
  203. $attr{$name}{OnlineStatus}='available';
  204. if(defined($server) && defined($port) && defined($username) && defined($password) && defined($tls) && defined($ssl))
  205. {
  206. $hash->{helper}{server} = $server;
  207. $hash->{helper}{username} = $username;
  208. $hash->{helper}{password} = $password;
  209. $hash->{helper}{port} = $port;
  210. $hash->{helper}{tls} = $tls;
  211. $hash->{helper}{ssl} = $ssl;
  212. $hash->{helper}{otractive} = 0;
  213. $hash->{helper}{otrJIDs} = {}; #hash
  214. if ($tls == 1 || $ssl == 1) {
  215. if(!eval("require Net::SSLeay;")) {
  216. $hash->{STATE} = "Disconnected (Module error)";
  217. $hash->{CONNINFO} = "Missing perl Module Net::SSLeay for TLS or SSL connection.";
  218. return undef;
  219. }
  220. }
  221. if(!eval("require Authen::SASL;")) {
  222. $hash->{STATE} = "Disconnected (Module error)";
  223. $hash->{CONNINFO} = "Missing perl Module Authen::SASL for Jabber Authentication.";
  224. return undef;
  225. }
  226. Jabber_CheckConnection($hash) if($init_done);
  227. InternalTimer(gettimeofday()+$attr{$name}{PollTimer}, "Jabber_PollMessages", $hash,0);
  228. return undef;
  229. }
  230. else
  231. {
  232. return "define not correct: define <name> Jabber <server> <port> <username> <password> <tls> <ssl>";
  233. }
  234. }
  235. ###################################
  236. sub
  237. Jabber_UnDef($$)
  238. {
  239. my ($hash, $name) = @_;
  240. RemoveInternalTimer($hash);
  241. $hash->{JabberDevice}->Disconnect();
  242. return undef;
  243. }
  244. ###################################
  245. # Attrib
  246. sub
  247. Jabber_Attr(@)
  248. {
  249. my ($cmd,$name,$aName,$aVal) = @_;
  250. my $hash = $defs{$name};
  251. # $cmd can be "del" or "set"
  252. # $name is device name
  253. # aName and aVal are Attribute name and value
  254. if ($cmd eq "set") {
  255. if ($aName eq "OnlineStatus") {
  256. if (defined($aVal) && defined($hash->{JabberDevice}) && $init_done) {
  257. #Send Presence type only if we do not want to be available
  258. if ($aVal ne "available") {
  259. $hash->{JabberDevice}->PresenceSend(type=>$aVal);
  260. } else {
  261. $hash->{JabberDevice}->PresenceSend();
  262. }
  263. }
  264. } elsif ($aName eq "MucJoin") {
  265. #Join the MUC
  266. if (defined($aVal) && defined($hash->{JabberDevice}) && $init_done) {
  267. Jabber_MUCs_Join($hash,$aVal);
  268. }
  269. } elsif ($aName eq "OTREnable") {
  270. #We dont care if Jabber is not connected already
  271. if (defined($aVal) && $init_done) {
  272. #OTR Enabled, init OTR
  273. if ($aVal == 1) {
  274. Jabber_OTR_Init($hash);
  275. }
  276. }
  277. } elsif ($aName eq "OTRSharedSecret") {
  278. #Nothing special to do will be used later..
  279. } elsif ($aName eq "JabberDomain" && $init_done) {
  280. #restart connection...
  281. $hash->{JabberDevice}->Disconnect();
  282. }
  283. }
  284. return undef;
  285. }
  286. ##########################################
  287. # Joins a MUC and save the nick/name for later processing
  288. sub
  289. Jabber_MUCs_Join($$)
  290. {
  291. my ($hash,$MUCJID) = @_;
  292. my $name = $hash->{NAME};
  293. #find rooms to leave
  294. my %oldrooms;
  295. if (defined($hash->{helper}{myMUCJIDs})) {
  296. foreach my $oldroom (@{$hash->{helper}{myMUCJIDs}}) {
  297. $oldrooms{$oldroom} = 1;
  298. }
  299. }
  300. $hash->{helper}{myMUCJIDs} = ();
  301. #format of line: room@server/nick:pass,room2@server/nick2:pass
  302. my @rooms = split /,/, $MUCJID;
  303. foreach my $roompass (@rooms) {
  304. my ($room,$pass) = split /:/,$roompass;
  305. #add room to array
  306. push @{ $hash->{helper}{myMUCJIDs} }, $room;
  307. #remove from rooms to leave
  308. if (exists($oldrooms{$room})) {
  309. delete $oldrooms{$room};
  310. }
  311. #create new presence object
  312. my $presence = Net::Jabber::Presence->new;
  313. $presence->SetTo($room);
  314. my $muc = $presence->NewChild('http://jabber.org/protocol/muc');
  315. if($pass) {
  316. $muc->SetPassword($pass);
  317. }
  318. #remove history
  319. my $hist = $muc->AddHistory();
  320. $hist->SetMaxChars(0);
  321. #join the room (or change the nick)
  322. $hash->{JabberDevice}->Send($presence);
  323. }
  324. #leave old rooms
  325. foreach my $room (keys %oldrooms) {
  326. $hash->{JabberDevice}->PresenceSend(to => $room, type => 'unavailable');
  327. }
  328. }
  329. ##########################################
  330. # Checking for waiting Messages from the Jabber Server
  331. sub
  332. Jabber_PollMessages($)
  333. {
  334. my ($hash) = @_;
  335. my $name = $hash->{NAME};
  336. my $connectiondied = 0;
  337. RemoveInternalTimer($hash);
  338. if(!$init_done) {
  339. InternalTimer(gettimeofday()+$attr{$name}{PollTimer}, "Jabber_PollMessages", $hash,0);
  340. return undef; # exit if FHEM is not ready yet.
  341. }
  342. if (Jabber_CheckConnection($hash)) {
  343. Log 0, "$hash->{NAME} Jabber PollMessages" if $debug;
  344. #We need to manually do what XML::Stream normally do on 'Process()' as we do not want to block it for too long.
  345. #They only accept a multiple of second as timeout, but that is too much if we block FHEM every second a second
  346. #If we find that there is something to do we call Process()
  347. my $doProcess = 0;
  348. #If there is something to read from the XMPP Server
  349. if (defined($hash->{JabberDevice}->{STREAM}->{SELECT}->can_read(0.01))) {
  350. $doProcess = 1;
  351. }
  352. #From XML::Stream - Check if a connection needs a keepalive or has been timed out.
  353. #Again, we would block for at least one second (every 10 seconds) if we call Process() here
  354. if ($doProcess == 0) {
  355. #From XML::Stream - Check if a connection needs a keepalive, and send that keepalive.
  356. foreach my $sid (keys(%{$hash->{JabberDevice}->{STREAM}->{SIDS}}))
  357. {
  358. next if ($sid eq "default");
  359. next if ($sid =~ /^server/);
  360. next if ($hash->{JabberDevice}->{STREAM}->{SIDS}->{$sid}->{status} == -1);
  361. if ((time - $hash->{JabberDevice}->{STREAM}->{SIDS}->{$sid}->{keepalive}) > 10)
  362. {
  363. $hash->{JabberDevice}->{STREAM}->IgnoreActivity($sid,1);
  364. $hash->{JabberDevice}->{STREAM}->{SIDS}->{$sid}->{status} = -1 if !defined($hash->{JabberDevice}->{STREAM}->Send($sid," "));
  365. if (! $hash->{JabberDevice}->{STREAM}->{SIDS}->{$sid}->{status} == 1)
  366. {
  367. #Keep-Alive failed - we must call Process() to handle it
  368. $doProcess = 1;
  369. Log 0, "$hash->{NAME} Keep Alive Failed" if $debug;
  370. }
  371. $hash->{JabberDevice}->{STREAM}->IgnoreActivity($sid,0);
  372. }
  373. }
  374. #From XML::Stream - Check if a connection timed out, if not respond, if it timed out, call Process()
  375. foreach my $sid (keys(%{$hash->{JabberDevice}->{STREAM}->{SIDS}}))
  376. {
  377. next if ($sid eq "default");
  378. next if ($sid =~ /^server/);
  379. $hash->{JabberDevice}->{STREAM}->Respond($sid)
  380. if (exists($hash->{JabberDevice}->{STREAM}->{SIDS}->{$sid}->{activitytimeout}) &&
  381. defined($hash->{JabberDevice}->{STREAM}->GetRoot($sid)));
  382. $doProcess = 1
  383. if (exists($hash->{JabberDevice}->{STREAM}->{SIDS}->{$sid}->{activitytimeout}) &&
  384. ((time - $hash->{JabberDevice}->{STREAM}->{SIDS}->{$sid}->{activitytimeout}) > 10) &&
  385. ($hash->{JabberDevice}->{STREAM}->{SIDS}->{$sid}->{status} != 1));
  386. }
  387. }
  388. #We do Process() - if the connection has died we reconnect.
  389. if ($doProcess == 1) {
  390. Log 0, "$hash->{NAME} DoProcess Call" if $debug;
  391. #Check for previous errors in process(), before XMPP::Connection will break down FHEM
  392. $connectiondied = 0;
  393. if (defined($hash->{JabberDevice})) {
  394. if (exists($hash->{JabberDevice}->{PROCESSERROR}) && ($hash->{JabberDevice}->{PROCESSERROR} == 1)) {
  395. #XMPP::Connection would kill FHEM now.. But we try to handle it.
  396. $hash->{STATE} = "Disconnected";
  397. $hash->{CONNINFO} = "Jabber connection error (Previous XMPP Process() error!)";
  398. Log 0, "$hash->{NAME} Jabber connection error (Previous XMPP Process() error!)" if $debug;
  399. $connectiondied = 1;
  400. } else {
  401. #Do Process(), if it is undef, connection is gone or some other problem...
  402. if (!defined($hash->{JabberDevice}->Process(1))) {
  403. $hash->{STATE} = "Disconnected";
  404. $hash->{CONNINFO} = "Jabber connection died";
  405. Log 0, "$hash->{NAME} Jabber connection error (Process() is undef!)" if $debug;
  406. $connectiondied = 1;
  407. }
  408. }
  409. } else {
  410. $connectiondied = 1;
  411. }
  412. if ($connectiondied == 1) {
  413. #connection died
  414. Log 0, "$hash->{NAME} Connection died" if $debug;
  415. $hash->{JabberDevice} = undef;
  416. if (Jabber_CheckConnection($hash)) {
  417. #Send Presence type only if we do not want to be availible
  418. if ($attr{$name}{OnlineStatus} ne "available") {
  419. $hash->{JabberDevice}->PresenceSend(type=>$attr{$name}{OnlineStatus});
  420. } else {
  421. $hash->{JabberDevice}->PresenceSend();
  422. }
  423. }
  424. }
  425. }
  426. Log 0, "$hash->{NAME} Poll End" if $debug;
  427. }
  428. InternalTimer(gettimeofday()+$attr{$name}{PollTimer}, "Jabber_PollMessages", $hash,0);
  429. }
  430. ##########################################
  431. # Checking the Connection to the Jabber Server
  432. sub Jabber_CheckConnection($)
  433. {
  434. my ($hash) = @_;
  435. my $name = $hash->{NAME};
  436. if (!defined($hash->{JabberDevice})) {
  437. #Not defined, create a new Jabber connection
  438. my $dev = undef;
  439. if ($debug > 0) {
  440. $dev = new Net::Jabber::Client(debuglevel=>2,debugfile=>"/tmp/jabberdebug.log");
  441. } else {
  442. $dev = new Net::Jabber::Client();
  443. }
  444. $hash->{JabberDevice} = $dev;
  445. #Default to SSL = nonverify (0x00) - this has been changed in XML::Stream 1.23_04 and cause problems because you need a CA verify list.
  446. if (defined($hash->{JabberDevice}->{STREAM}->{SIDS}->{default}->{ssl_verify})) {
  447. $hash->{JabberDevice}->{STREAM}->{SIDS}->{default}->{ssl_verify} = 0x00;
  448. }
  449. #Default to to SRV lookups, ugly hack because older versions of XMPP::Connection dont call the respective value in XML::Stream..
  450. $hash->{JabberDevice}->{STREAM}->{SIDS}->{default}->{srv} = "_xmpp-client._tcp";
  451. #fix for weak callbacks, since Net::XMPP v.1.05 they "weaken" the reference to prevent *possible* memory problems,
  452. #but that causes the callbacks to not work anymore, so we unweaken it here by initializing the callbacks again :)
  453. $hash->{JabberDevice}->InitCallbacks();
  454. #For MUC we need to check if the history function is in the namespace, if not our libraries are old and we need to hack it in
  455. #I found this option in NET::Jabber::Owl
  456. if (!exists($Net::XMPP::Namespaces::NS{'__netjabber__:iq:muc:history'})) {
  457. $hash->{JabberDevice}->AddNamespace(ns => '__netjabber__:iq:muc:history',
  458. tag => 'history',
  459. xpath => {
  460. MaxChars => { path => '@maxchars' },
  461. MaxStanzas => { path => '@maxstanzas' },
  462. Seconds => { path => '@seconds' },
  463. Since => { path => '@since' }
  464. },
  465. docs => {
  466. module => 'Net::Jabber',
  467. },
  468. );
  469. #patch the already existing muc namespace to support the history function so we can call "AddHistory" later...
  470. $Net::XMPP::Namespaces::NS{'http://jabber.org/protocol/muc'}->{xpath}->{History} = {
  471. type => 'child',
  472. path => 'history',
  473. child => { ns => '__netjabber__:iq:muc:history' },
  474. calls => ['Add', 'Get', 'Set', 'Defined' ],
  475. };
  476. }
  477. #Needed for Message handling:
  478. $hash->{JabberDevice}->SetMessageCallBacks(normal => sub { \&Jabber_INC_Message($hash,@_) }, chat => sub { \&Jabber_INC_Message($hash,@_) }, groupchat => sub { \&Jabber_INC_MUCMessage($hash,@_) } );
  479. #Needed if someone wants to subscribe to us and is on the WhiteList
  480. $hash->{JabberDevice}->SetPresenceCallBacks(
  481. subscribe => sub { \&Jabber_INC_Subscribe($hash,@_) },
  482. subscribed => sub { \&Jabber_INC_Subscribe($hash,@_) },
  483. available => sub { \&Jabber_INC_Subscribe($hash,@_) },
  484. unavailable => sub { \&Jabber_INC_Subscribe($hash,@_) },
  485. unsubscribe => sub { \&Jabber_INC_Subscribe($hash,@_) },
  486. unsubscribed => sub { \&Jabber_INC_Subscribe($hash,@_) },
  487. error => sub { \&Jabber_INC_Subscribe($hash,@_) }
  488. );
  489. if(exists($attr{$name}{OTREnable}) && $attr{$name}{OTREnable} == 1) {
  490. Jabber_OTR_Init($hash);
  491. }
  492. }
  493. if (!$hash->{JabberDevice}->Connected()) {
  494. my $componentname = $hash->{helper}{server};
  495. if(exists($attr{$name}{JabberDomain}) && $attr{$name}{JabberDomain} ne '') {
  496. $componentname = $attr{$name}{JabberDomain};
  497. }
  498. my $connectionstatus = $hash->{JabberDevice}->Connect(
  499. hostname=>$hash->{helper}{server},
  500. port=>$hash->{helper}{port},
  501. tls=>$hash->{helper}{tls},
  502. ssl=>$hash->{helper}{ssl},
  503. componentname=>$componentname
  504. );
  505. if (!defined($connectionstatus)) {
  506. $hash->{STATE} = "Disconnected";
  507. $hash->{CONNINFO} = "Jabber connect error ($!)";
  508. return 0;
  509. }
  510. my @authresult = $hash->{JabberDevice}->AuthSend(username=>$hash->{helper}{username},
  511. password=>$hash->{helper}{password},
  512. resource=>$attr{$name}{ResourceName});
  513. if (!defined($authresult[0])) {
  514. $hash->{STATE} = "Disconnected";
  515. $hash->{CONNINFO} = "Jabber authentication error: Cannot Authenticate for an unknown reason. Connectionstatus is: $connectionstatus";
  516. return 0;
  517. }
  518. if ($authresult[0] ne "ok") {
  519. $hash->{STATE} = "Disconnected";
  520. $hash->{CONNINFO} = "Jabber authentication error: @authresult";
  521. return 0;
  522. }
  523. $hash->{STATE} = "Connected";
  524. $hash->{CONNINFO} = "Connected to $hash->{helper}{server} with username $hash->{helper}{username}";
  525. $hash->{JabberDevice}->RosterRequest();
  526. #join MUCs
  527. if (defined($attr{$name}{MucJoin})) {
  528. Jabber_MUCs_Join($hash,$attr{$name}{MucJoin}) if $attr{$name}{MucJoin} ne "";
  529. }
  530. #Send Presence type only if we do not want to be availible
  531. if ($attr{$name}{OnlineStatus} ne "available") {
  532. $hash->{JabberDevice}->PresenceSend(type=>$attr{$name}{OnlineStatus});
  533. } else {
  534. $hash->{JabberDevice}->PresenceSend();
  535. }
  536. }
  537. if (!$hash->{JabberDevice}->Connected()) {
  538. $hash->{STATE} = "Disconnected";
  539. $hash->{CONNINFO} = "Cannot connect for an unknown reason";
  540. return 0;
  541. } else {
  542. return 1;
  543. }
  544. }
  545. ##########################################
  546. # Incoming Subscribe events
  547. sub Jabber_INC_Subscribe
  548. {
  549. my($hash,$session_id, $presence) = @_;
  550. my $name = $hash->{NAME};
  551. Log 0, "$hash->{NAME} INC_Subscribe: Recv presence from: " . $presence->GetFrom() . " Type: ". $presence->GetType() if $debug;
  552. my $sender = $presence->GetFrom();
  553. my $JID = new Net::Jabber::JID($sender);
  554. my $senderShort = $JID->GetJID("base");
  555. my $senderLong = $JID->GetJID("full");
  556. my $mucRegexMatch = 0;
  557. #Check the Whitelist if the sender is allowed to send us.
  558. if (defined($attr{$name}{MucRecvWhitelist})) {
  559. if ($senderLong =~ m/$attr{$name}{MucRecvWhitelist}/) {
  560. $mucRegexMatch = 1;
  561. }
  562. }
  563. if ($senderShort =~ m/$attr{$name}{RecvWhitelist}/ || $mucRegexMatch) {
  564. Log 0, "$hash->{NAME} Regex m/$attr{$name}{RecvWhitelist}/ matched" if $debug && $senderShort =~ m/$attr{$name}{RecvWhitelist}/;
  565. Log 0, "$hash->{NAME} Regex (MUC) m/$attr{$name}{MucRecvWhitelist}/ matched" if $debug && $mucRegexMatch && $senderLong =~ m/$attr{$name}{MucRecvWhitelist}/;
  566. if ($presence->GetType() eq "subscribe") {
  567. #respond with authorization so they can see our online state
  568. $hash->{JabberDevice}->Subscription(type=>"subscribed",
  569. to=>$presence->GetFrom());
  570. #ask for authorization also so we can also see their online state (for future)
  571. $hash->{JabberDevice}->Subscription(type=>"subscribe",
  572. to=>$presence->GetFrom());
  573. }
  574. } else {
  575. Log 0, "$hash->{NAME} Regex m/$attr{$name}{RecvWhitelist}/ and m/$attr{$name}{MucRecvWhitelist}/ did not match" if $debug;
  576. }
  577. }
  578. ##########################################
  579. # Incoming Private (encrypted or plaintext) Message
  580. sub Jabber_INC_Message {
  581. my($hash,$session_id, $xmpp_message) = @_;
  582. my $name = $hash->{NAME};
  583. my $sender = $xmpp_message->GetFrom();
  584. my $message = $xmpp_message->GetBody();
  585. utf8::encode($message);
  586. Log 0, "$hash->{NAME} INC_Message: $sender: $message" if $debug;
  587. my $JID = new Net::Jabber::JID($sender);
  588. my $senderShort = $JID->GetJID("base");
  589. #Check the Whitelist if the sender is allowed to send us, but not the "shortname" as this will strip the sendernickname off
  590. if ($senderShort =~ m/$attr{$name}{RecvWhitelist}/) {
  591. Log 0, "$hash->{NAME} Regex m/$attr{$name}{RecvWhitelist}/ matched" if $debug;
  592. # check to see if this is a OTR Message, if OTR is enabled
  593. my $otr_message_recv = 0;
  594. if ($hash->{helper}{otractive}) {
  595. if ($message =~ m/^\?OTR/) {
  596. #try to decrypt it
  597. my $discard_msg = 0;
  598. ($message, $discard_msg) = $hash->{OTR}->decrypt($JID->GetJID("full"), $message);
  599. if (!$discard_msg && $message ne "") {
  600. Log 0, "$hash->{NAME} INC_Message [OTR]: $sender: $message" if $debug;
  601. utf8::encode($message);
  602. $otr_message_recv = 1;
  603. } elsif(!$discard_msg && $message eq "") {
  604. Log 0, "$hash->{NAME} INC_Message [OTR]: We received an encrypted message from $senderShort but were unable to decrypt it (maybe also a control message)" if $debug;
  605. }
  606. }
  607. }
  608. #When we have got no message after the OTR decrypt, we can leave this function.
  609. if (!defined($message) || $message eq "") {
  610. Log 0, "$hash->{NAME} Message is empty after OTR decrypt." if $debug;
  611. return undef;
  612. }
  613. # Some IM clients send HTML, we need
  614. # to convert it to plain text
  615. # remove tags
  616. $message =~ s/<(.|\n)+?>//g;
  617. # convert "'s
  618. $message =~ s/"/\\"/g;
  619. # trim whitespaces at beginning and end
  620. $message =~ s/^[\n\r\s]+|[\n\r\s]+$//g;
  621. #now, if the message is empty, (or was only filled with xml tags for various status infos), drop it
  622. if ($message ne "") {
  623. readingsBeginUpdate($hash);
  624. if ($otr_message_recv) {
  625. readingsBulkUpdate($hash,"OTRMessage","$sender: $message");
  626. readingsBulkUpdate($hash,"OTRLastSenderJID","$sender");
  627. readingsBulkUpdate($hash,"OTRLastMessage","$message");
  628. Log 0, "$hash->{NAME} ReadingsUpdate [OTR]: $message" if $debug;
  629. } else {
  630. readingsBulkUpdate($hash,"Message","$sender: $message");
  631. readingsBulkUpdate($hash,"LastSenderJID","$sender");
  632. readingsBulkUpdate($hash,"LastMessage","$message");
  633. Log 0, "$hash->{NAME} ReadingsUpdate: $message" if $debug;
  634. }
  635. readingsEndUpdate($hash, 1);
  636. } else {
  637. Log 0, "$hash->{NAME} Message was empty or full of xml tags - no readings update" if $debug;
  638. }
  639. } else {
  640. Log 0, "$hash->{NAME} Regex m/$attr{$name}{RecvWhitelist}/ did not match" if $debug;
  641. }
  642. }
  643. ##########################################
  644. # Incoming MUC (Multi-User-Channel) Message
  645. sub Jabber_INC_MUCMessage {
  646. my($hash,$session_id, $xmpp_message) = @_;
  647. my $name = $hash->{NAME};
  648. my $sender = $xmpp_message->GetFrom();
  649. my $message = $xmpp_message->GetBody();
  650. utf8::encode($message);
  651. Log 0, "$hash->{NAME} INC_MUCMessage: $sender: $message\n" if $debug;
  652. my $JID = new Net::Jabber::JID($sender);
  653. my $senderShort = $JID->GetJID("base");
  654. my $senderLong = $JID->GetJID("full");
  655. #filter MUC messages (ie subject set on join)
  656. #filter own messages to prevent loop
  657. foreach my $muc (@{$hash->{helper}{myMUCJIDs}}) {
  658. my $mucJID = new Net::Jabber::JID($muc);
  659. if ($JID->GetJID("full") eq $mucJID->GetJID("base")) {
  660. #room send something to us
  661. Log 0, "$hash->{NAME} ignoring message from room $senderShort" if $debug;
  662. return undef;
  663. } elsif ($JID->GetJID("full") eq $mucJID->GetJID("full")) {
  664. #we received our own message
  665. Log 0, "$hash->{NAME} ignoring message from ourself" if $debug;
  666. return undef;
  667. }
  668. }
  669. #Check the Whitelist if the sender is allowed to send us, but not the "shortname" as this will strip the sendernickname off
  670. if ($senderLong =~ m/$attr{$name}{MucRecvWhitelist}/) {
  671. Log 0, "$hash->{NAME} Regex (MUC) m/$attr{$name}{MucRecvWhitelist}/ matched" if $debug;
  672. # Some IM clients send HTML, we need
  673. # to convert it to plain text
  674. # remove tags
  675. $message =~ s/<(.|\n)+?>//g;
  676. # convert "'s
  677. $message =~ s/"/\\"/g;
  678. # trim whitespaces at beginning and end
  679. $message =~ s/^[\n\r\s]+|[\n\r\s]+$//g;
  680. #now, if the message is empty, (or was only filled with xml tags for various status infos), drop it
  681. if ($message ne "") {
  682. readingsBeginUpdate($hash);
  683. readingsBulkUpdate($hash,"MucMessage","$sender: $message");
  684. readingsBulkUpdate($hash,"MucLastSenderJID","$sender");
  685. readingsBulkUpdate($hash,"MucLastMessage","$message");
  686. Log 0, "$hash->{NAME} ReadingsUpdate: $message" if $debug;
  687. readingsEndUpdate($hash, 1);
  688. } else {
  689. Log 0, "$hash->{NAME} Message was empty or full of xml tags - no readings update" if $debug;
  690. }
  691. } else {
  692. Log 0, "$hash->{NAME} Regex (MUC) m/$attr{$name}{MucRecvWhitelist}/ did not match" if $debug;
  693. }
  694. }
  695. ##########################################
  696. # OTR Specific functions
  697. ##########################################
  698. sub
  699. Jabber_OTR_Init($)
  700. {
  701. my ($hash) = @_;
  702. #check if Crypt::OTR is installed
  703. if(!eval("require Crypt::OTR;")) {
  704. $hash->{helper}{otractive} = 0;
  705. $hash->{STATE} = $hash->{STATE}. " (OTR Error)";
  706. $hash->{OTR_STATE} = "Missing perl Module Crypt::OTR, OTR disabled.";
  707. # $hash->{CONNINFO} = "Missing perl Module Crypt::OTR, OTR disabled.";
  708. return undef;
  709. }
  710. #find if the current directory is writeable to store our key, if not we will use /tmp as this is the most availible one.
  711. my $otrCfgDir = AttrVal('global','modpath','.')."/log";
  712. $otrCfgDir = "/tmp" if ! -e $otrCfgDir || ! -w $otrCfgDir;
  713. Crypt::OTR->init;
  714. my $otr_accname = $hash->{NAME};
  715. my $otr_proto = "FHEMJabber";
  716. my $otr = new Crypt::OTR(
  717. account_name => $otr_accname,
  718. protocol => $otr_proto,
  719. config_dir => $otrCfgDir,
  720. );
  721. $hash->{OTR} = $otr;
  722. $hash->{OTR}->set_callback('inject' => sub { \&Jabber_OTR_inject($hash,@_) });
  723. $hash->{OTR}->set_callback('otr_message' => sub { \&Jabber_OTR_system_message($hash,@_) });
  724. $hash->{OTR}->set_callback('verified' => sub { \&Jabber_OTR_connected_verified($hash,@_) });
  725. $hash->{OTR}->set_callback('unverified' => sub { \&Jabber_OTR_connected_unverified($hash,@_) });
  726. $hash->{OTR}->set_callback('disconnect' => sub { \&Jabber_OTR_disconnected($hash,@_) });
  727. $hash->{OTR}->set_callback('smp_request' => sub { \&Jabber_OTR_smprequest($hash,@_) });
  728. if (! -e $otrCfgDir."/otr.private_key-".lc($otr_accname)."-".lc($otr_proto)) {
  729. #say we are genning Private key, and log the info, then execute it in another fork of fhem to prevent a 2h block
  730. Log 0, "$hash->{NAME} Generating OTR private key, be prepared that this will take 2 hours or more. Check OTR_STATE (this is a one-time task)";
  731. $hash->{OTR_STATE} = "Generating OTR private key...";
  732. if(!exists($hash->{helper}{OTR_GENKEY_PID})) {
  733. $hash->{helper}{OTR_GENKEY_PID} = BlockingCall("Jabber_OTR_GenPrivateKey", $hash->{NAME}."|".$otr_accname."|".$otr_proto."|".$otrCfgDir, "Jabber_OTR_GenPrivateKeyComplete");
  734. } else {
  735. $hash->{OTR_STATE} = "Still generating OTR private key. Please be patient!";
  736. }
  737. } else {
  738. if(!exists($hash->{helper}{OTR_GENKEY_PID})) {
  739. #Private key is there, everything is fine.
  740. Log 0, "$hash->{NAME} OTR found privatekey, good!" if $debug;
  741. $hash->{helper}{otractive} = 1;
  742. $hash->{OTR_STATE} = "OTR enabled and active";
  743. Log 3, "$hash->{NAME} OTR successfully enabled and active" if $debug;
  744. } else {
  745. $hash->{OTR_STATE} = "Still generating OTR private key. Please be patient!";
  746. Log 3, "$hash->{NAME} OTR still generating OTR private key. Please be patient!";
  747. }
  748. }
  749. }
  750. ##########################################
  751. # Generating private key in another process via Blocking.pm
  752. sub Jabber_OTR_GenPrivateKey($)
  753. {
  754. my ($callargs) = @_;
  755. my ($hashname, $otr_accname,$otr_proto,$otrCfgDir) = split("\\|", $callargs);
  756. my $otr = new Crypt::OTR(
  757. account_name => $otr_accname,
  758. protocol => $otr_proto,
  759. config_dir => $otrCfgDir,
  760. );
  761. $otr->load_privkey();
  762. return "$hashname";
  763. }
  764. ##########################################
  765. # Completing generating private key
  766. sub Jabber_OTR_GenPrivateKeyComplete($)
  767. {
  768. my ($hashname) = @_;
  769. return unless(defined($hashname));
  770. my $hash = $defs{$hashname};
  771. $hash->{OTR_STATE} = "Finished generating OTR private key. OTR is now active.";
  772. Log 0, "$hash->{NAME} Finished generating OTR private key";
  773. delete($hash->{helper}{OTR_GENKEY_PID});
  774. $hash->{helper}{otractive} = 1;
  775. log 0, "$hash->{NAME} OTR successfully enabled and active" if $debug;
  776. }
  777. ##########################################
  778. # called when OTR is ready to send a message after function calls (e.g. decrypt / smp / etc).
  779. sub Jabber_OTR_inject {
  780. my ($hash, $self, $account_name, $protocol, $dest_account, $message) = @_;
  781. Log 0, "$hash->{NAME} [OTR Inject] Inject called: $message" if $debug;
  782. Jabber_Set_Message($hash, $dest_account, $message);
  783. #most times we await an answer, ignore the polltimer and check for new messages immediantly
  784. Jabber_PollMessages($hash);
  785. }
  786. ##########################################
  787. # called to display an OTR control message for a particular user or protocol
  788. sub Jabber_OTR_system_message {
  789. my ($hash, $self, $account_name, $protocol, $other_user, $otr_message) = @_;
  790. Log 0, "$hash->{NAME} [OTR Sys MSG] $otr_message" if $debug;
  791. return 1;
  792. }
  793. ##########################################
  794. #called when an OTR Session has been established and has been verified by the SMP Protocol
  795. sub Jabber_OTR_connected_verified {
  796. my ($hash, $self, $from_account) = @_;
  797. Log 0, "$hash->{NAME} [OTR] verified connection with $from_account established" if $debug;
  798. $hash->{helper}{otrJIDs}{$from_account}{verified} = 1;
  799. #after this callback, OTR sends another message before the connection is fully established, so we have to delay that again for 5 secs before sending the actual message
  800. my %h = (hash => $hash, from_account => $from_account);
  801. InternalTimer(gettimeofday()+5, "Jabber_OTRDelaySend", \%h,0);
  802. }
  803. ##########################################
  804. #called when an OTR Session has been established and is not verified
  805. sub Jabber_OTR_connected_unverified {
  806. my ($hash, $self, $from_account) = @_;
  807. Log 0, "$hash->{NAME} [OTR] unverified connection with $from_account established" if $debug;
  808. $hash->{helper}{otrJIDs}{$from_account}{verified} = 0;
  809. #after this callback, OTR sends another message before the connection is fully established, so we have to delay that again for 5 secs before sending the actual message
  810. my %h = (hash => $hash, from_account => $from_account);
  811. InternalTimer(gettimeofday()+5, "Jabber_OTRDelaySend", \%h,0);
  812. }
  813. ##########################################
  814. #called when the other end want to verify our identity
  815. sub Jabber_OTR_smprequest {
  816. my ($hash, $self, $account_name, $other_user) = @_;
  817. my $name = $hash->{NAME};
  818. Log 0, "$hash->{NAME} [OTR] User $other_user wants to verify our identity, sending shared secret response" if $debug;
  819. if (defined($attr{$name}{OTRSharedSecret})) {
  820. $hash->{OTR}->continue_smp($other_user, $attr{$name}{OTRSharedSecret});
  821. } else {
  822. Log 0, "$hash->{NAME} [OTR] Error, no shared secret defined, sending bogus secret" if $debug;
  823. $hash->{OTR}->continue_smp($other_user, "ImaBogusSecretBecauseNothingDefined");
  824. }
  825. }
  826. ##########################################
  827. # Delayed sending message after established a secure connection
  828. # This is needed because AFTER the function "un/verified" is called
  829. # the system is still in the process of opening the encrypted communication
  830. #
  831. sub Jabber_OTRDelaySend($$) {
  832. my $h = shift;
  833. my $hash = $h->{hash};
  834. my $from_account = $h->{from_account};
  835. #if we have unsent messages, send them now.
  836. if (defined($hash->{helper}{otrJIDs}{$from_account}{waitingMsgs})) {
  837. foreach my $waitingMsg (@{$hash->{helper}{otrJIDs}{$from_account}{waitingMsgs}}) {
  838. Jabber_Set_OTRMessage($hash,$waitingMsg->{jid},$waitingMsg->{msg});
  839. }
  840. }
  841. }
  842. ##########################################
  843. #called when an OTR Session has been disconnected
  844. sub Jabber_OTR_disconnected {
  845. my ($hash, $self, $from_account) = @_;
  846. Log 0, "$hash->{NAME} [OTR] $from_account disconnected secure channel" if $debug;
  847. delete ($hash->{helper}{otrJIDs}{$from_account});
  848. }
  849. 1;
  850. =pod
  851. =item device
  852. =item summary connect FHEM to the Jabber Network, send and receiving messages
  853. =item summary_DE verbindet FHEM and Jabber Netz, kann Nachrichten senden und empfangen
  854. =begin html
  855. <a name="Jabber"></a>
  856. <h3>Jabber</h3>
  857. <ul>
  858. This Module allows FHEM to connect to the Jabber Network, send and receiving messages from and to a Jabber server.<br>
  859. <br>
  860. Jabber is another description for (XMPP) - a communications protocol for message-oriented middleware based
  861. on XML and - depending on the server - encrypt the communications channels.<br>
  862. For the user it is similar to other instant messaging Platforms like Facebook Chat, ICQ or Google's Hangouts
  863. but free, Open Source and by default encrypted between the Jabber servers.<br>
  864. <br>
  865. You need an account on a Jabber Server, you can find free services and more information on <a href="http://www.jabber.org/">jabber.org</a><br>
  866. Discuss the module in the <a href="http://forum.fhem.de/index.php/topic,18967.0.html">specific thread here</a>.<br>
  867. <br>
  868. This Module requires the following perl Modules to be installed (using SSL):<br>
  869. <ul>
  870. <li>Net::Jabber</li>
  871. <li>Net::XMPP</li>
  872. <li>Authen::SASL</li>
  873. <li>XML::Stream</li>
  874. <li>Net::SSLeay</li>
  875. </ul>
  876. <br>
  877. Since version 1.5 it allows FHEM also to join MUC (Multi-User-Channels) and the use of OTR for end to end encryption<br>
  878. If you want to use OTR you must compile and install Crypt::OTR from CPAN on your own.<br>
  879. <br>
  880. <br>
  881. <a name="JabberDefine"></a>
  882. <b>Define</b>
  883. <ul>
  884. <code>define &lt;name&gt; Jabber &lt;server&gt; &lt;port&gt; &lt;username&gt; &lt;password&gt; &lt;TLS&gt; &lt;SSL&gt;</code><br>
  885. <br>
  886. You have to create an account on a free Jabber server or setup your own Jabber server.<br>
  887. <br>
  888. Example:
  889. <ul>
  890. <code>define JabberClient1 Jabber jabber.org 5222 myusername mypassword 1 0</code>
  891. </ul>
  892. <br>
  893. </ul>
  894. <br>
  895. <a name="JabberSet"></a>
  896. <b>Set</b>
  897. <ul>
  898. <li>
  899. <code>set &lt;name&gt; msg &lt;username&gt; &lt;msg&gt;</code>
  900. <br>
  901. sends a message to the specified username
  902. <br>
  903. Examples:
  904. <ul>
  905. <code>set JabberClient1 msg myname@jabber.org It is working!</code><br>
  906. </ul>
  907. </li>
  908. <br>
  909. <li>
  910. <code>set &lt;name&gt; msgmuc &lt;channel&gt; &lt;msg&gt;</code>
  911. <br>
  912. sends a message to the specified MUC group channel
  913. <br>
  914. Examples:
  915. <ul>
  916. <code>set JabberClient1 msgmuc roomname@jabber.org Woot!</code><br>
  917. </ul>
  918. </li>
  919. <br>
  920. <li>
  921. <code>set &lt;name&gt; msgotr &lt;username&gt; &lt;msg&gt;</code>
  922. <br>
  923. sends an Off-the-Record encrypted message to the specified username, if no OTR session is currently established it is being tried to esablish an OTR session with the specified user.<br>
  924. If the user does not have OTR support the message is discarded.
  925. <br>
  926. Examples:
  927. <ul>
  928. <code>set JabberClient1 msgotr myname@jabber.org Meet me at 7pm at the place today :*</code><br>
  929. </ul>
  930. </li>
  931. <br>
  932. <li>
  933. <code>set &lt;name&gt; subscribe &lt;username&gt;</code>
  934. <br>
  935. asks the username for authorization (not needed normally)
  936. <br>
  937. Example:
  938. <ul>
  939. <code>set JabberClient1 subscribe myname@jabber.org</code><br>
  940. </ul>
  941. </li>
  942. </ul>
  943. <br>
  944. <b>Get</b> <ul>N/A</ul><br>
  945. <a name="JabberAttr"></a>
  946. <b>Attributes</b>
  947. <ul>
  948. <a name="OnlineStatus"></a>
  949. <li><code>OnlineStatus available|unavailable</code><br>
  950. Sets the online status of the client, available (online in Clients) or unavailable (offline in Clients)<br>
  951. It is possible, on some servers, that FHEM can even recieve messages if the status is unavailable<br>
  952. <br>
  953. Default: <code>available</code>
  954. </li><br>
  955. <a name="ResourceName"></a>
  956. <li><code>ResourceName &lt;name&gt;</code><br>
  957. In XMPP/Jabber you can have multiple clients connected with the same username. <br>
  958. The resource name finally makes the Jabber-ID unique to each client.<br>
  959. Here you can define the resource name.<br>
  960. <br>
  961. Default: <code>FHEM</code>
  962. </li><br>
  963. <a name="PollTimer"></a>
  964. <li><code>PollTimer &lt;seconds&gt;</code><br>
  965. This is the interval in seconds at which the jabber server get polled.<br>
  966. Every interval the client checks if there are messages waiting and checks the connection to the server.<br>
  967. Don't set it over 10 seconds, as the client could get disconnected.<br>
  968. <br>
  969. Default: <code>2</code>
  970. </li><br>
  971. <a name="RecvWhitelist"></a>
  972. <li><code>RecvWhitelist &lt;Regex&gt;</code><br>
  973. Only if the Regex match, the client accepts and interpret the message. Everything else will be discarded.<br>
  974. <br>
  975. Default: <code>.*</code><br>
  976. Examples:<br>
  977. <ul>
  978. <code>myname@jabber.org</code><br>
  979. <code>(myname1@jabber.org|myname2@xmpp.de)</code><br>
  980. </ul>
  981. </li><br>
  982. <a name="MucJoin"></a>
  983. <li><code>MucJoin channel1@server.com/mynick[:password]</code><br>
  984. Allows you to join one or more MUC's (Multi-User-Channel) with a specific Nick and a optional Password<br>
  985. <br>
  986. Default: empty (no messages accepted)<br>
  987. Examples:<br>
  988. <ul>
  989. Join a channel: <code>channel1@server.com/mynick</code><br>
  990. Join more channels: <code>channel1@server.com/mynick,channel2@server.com/myothernick</code><br>
  991. Join a channel with a password set: <code>channel1@server.com/mynick:password</code><br>
  992. </ul>
  993. </li><br>
  994. <a name="MucRecvWhitelist"></a>
  995. <li><code>MucRecvWhitelist &lt;Regex&gt;</code><br>
  996. Same as RecvWhitelist but for MUC: Only if the Regex match, the client accepts and interpret the message. Everything else will be discarded.<br>
  997. <br>
  998. Default: empty (no messages accepted)<br>
  999. Examples:<br>
  1000. <ul>
  1001. All joined channels allowed: <code>.*</code><br>
  1002. Specific channel allowed only: <code>mychannel@jabber.org</code><br>
  1003. Specific Nick in channel allowed only: <code>mychannel@jabber.org/NickOfFriend</code><br>
  1004. </ul>
  1005. </li><br>
  1006. <a name="OTREnable"></a>
  1007. <li><code>OTREnable 1|0</code><br>
  1008. Enabled the use of Crypt::OTR for end to end encryption between a device and FHEM<br>
  1009. You must have Crypt::OTR installed and a private key is being generated the first time you enable this option<br>
  1010. Key generation can take more than 2 hours on a quiet system but will not block FHEM instead it will inform you if it has been finished<br>
  1011. Key generation is a one-time-task<br>
  1012. <br>
  1013. Default: empty (OTR disabled)
  1014. </li><br>
  1015. <a name="OTRSharedSecret"></a>
  1016. <li><code>OTRSharedSecret aSecretKeyiOnlyKnow@@*</code><br>
  1017. Optional shared secret to allow the other end to start a trust verification against FHEM with this shared key.<br>
  1018. If the user starts a trust verification process the fingerprint of the FHEM private key will be saved at the user's device and the connection is trusted.<br>
  1019. This will allow to inform the user if the private key has changed (ex. in Man-in-the-Middle attacks)<br>
  1020. <br>
  1021. Default: empty, please define a shared secret on your own.
  1022. </li><br>
  1023. </ul>
  1024. <br>
  1025. <a name="JabberReadings"></a>
  1026. <b>Generated Readings/Events:</b>
  1027. <ul>
  1028. <li>Private Messages
  1029. <ul>
  1030. <li><b>Message</b> - Complete message including JID and text</li>
  1031. <li><b>LastMessage</b> - Only text portion of the Message</li>
  1032. <li><b>LastSenderJID</b> - Only JID portion of the Message</li>
  1033. </ul>
  1034. </li><br>
  1035. <li>Encrypted Private Messages (if OTREnable=1)
  1036. <ul>
  1037. <li><b>OTRMessage</b> - Complete decrypted message including JID and text</li>
  1038. <li><b>OTRLastMessage</b> - Only text portion of the Message</li>
  1039. <li><b>OTRLastSenderJID</b> - Only JID portion of the Message</li>
  1040. </ul>
  1041. </li><br>
  1042. <li>MUC Room Messages (if MUCJoin is set)
  1043. <ul>
  1044. <li><b>MucMessage</b> - Complete message including room's JID and text</li>
  1045. <li><b>MucLastMessage</b> - Only text portion of the Message</li>
  1046. <li><b>MucLastSenderJID</b> - Only JID portion of the Message</li>
  1047. </ul>
  1048. </li>
  1049. </ul>
  1050. <br>
  1051. <a name="JabberNotes"></a>
  1052. <b>Author's Notes:</b>
  1053. <ul>
  1054. <li>You can react and reply on incoming private messages with a notify like this:<br>
  1055. <pre><code>define Jabber_Notify notify JabberClient1:Message.* {
  1056. my $lastsender=ReadingsVal("JabberClient1","LastSenderJID","0");
  1057. my $lastmsg=ReadingsVal("JabberClient1","LastMessage","0");
  1058. my $temperature=ReadingsVal("BU_Temperatur","temperature","0");
  1059. fhem("set JabberClient1 msg ". $lastsender . " Temp: ".$temperature);
  1060. }
  1061. </code></pre>
  1062. </li>
  1063. <li>You can react and reply on MUC messages with a notify like this, be aware that the nickname in $lastsender is stripped off in the msgmuc function<br>
  1064. <pre><code>define Jabber_Notify notify JabberClient1:MucMessage.* {
  1065. my $lastsender=ReadingsVal("JabberClient1","LastSenderJID","0");
  1066. my $lastmsg=ReadingsVal("JabberClient1","LastMessage","0");
  1067. my $temperature=ReadingsVal("BU_Temperatur","temperature","0");
  1068. fhem("set JabberClient1 msgmuc ". $lastsender . " Temp: ".$temperature);
  1069. }
  1070. </code></pre>
  1071. </li>
  1072. <li>You can react and reply on OTR private messages with a notify like this:<br>
  1073. <pre><code>define Jabber_Notify notify JabberClient1:OTRMessage.* {
  1074. my $lastsender=ReadingsVal("JabberClient1","LastSenderJID","0");
  1075. my $lastmsg=ReadingsVal("JabberClient1","LastMessage","0");
  1076. my $temperature=ReadingsVal("BU_Temperatur","temperature","0");
  1077. fhem("set JabberClient1 msgotr ". $lastsender . " Temp: ".$temperature);
  1078. }
  1079. </code></pre>
  1080. </li>
  1081. </ul>
  1082. </ul>
  1083. =end html
  1084. =begin html_DE
  1085. <a name="Jabber"></a>
  1086. <h3>Jabber</h3>
  1087. <ul>
  1088. Dieses Modul verbindet sich mit dem Jabber Netzwerk, sendet und empf&auml;ngt Nachrichten von und zu einem Jabber Server.<br>
  1089. <br>
  1090. Jabber ist eine andere Beschreibung f&uuml;r "XMPP", ein Kommunikationsprotokoll f&uuml;r Nachrichtenorientierte "middleware", basierend
  1091. auf XML.<br>
  1092. Fester bestandteil des Protokolls ist die Verschl&uuml;sselung zwischen Client und Server.<br>
  1093. F&uuml;r den Benutzer ist es &auml;hnlich anderer Chat-Plattformen wie zum Beispiel dem facebook Chat, ICQ oder Google Hangouts -
  1094. jedoch frei Verf&uuml;gbar, open Source und normalerweise Verschl&uuml;sselt (was Serverabh&auml;ngig ist).<br>
  1095. <br>
  1096. F&uuml;r dieses Modul brauchst du einen Account auf einem Jabber Server. Kostenlose accounts und Server findet man unter <a href="http://www.jabber.org/">jabber.org</a><br>
  1097. Diskussionen zu diesem Modul findet man im <a href="http://forum.fhem.de/index.php/topic,18967.0.html">FHEM Forum hier</a>.<br>
  1098. <br>
  1099. Dieses Modul ben&ouml;tigt die folgenden Perl Module (inkl. SSL M&ouml;glichkeit)<br>
  1100. <ul>
  1101. <li>Net::Jabber</li>
  1102. <li>Net::XMPP</li>
  1103. <li>Authen::SASL</li>
  1104. <li>XML::Stream</li>
  1105. <li>Net::SSLeay</li>
  1106. </ul>
  1107. <br>
  1108. Seit Version 1.5 kann dieses Modul in Multi-User-Channel (sogenannte MUC) beitreten und Off-the-Record (OTR) Ende-zu-Ende Verschl&uuml;sselung benutzen.<br>
  1109. Wenn du OTR benutzen m&ouml;chtest musst du dir Crypt::OTR von CPAN selbst installieren.<br>
  1110. OTR ist nochmal ein zus&auml;tzlicher Sicherheitsrelevater Punkt, da die Kommunikation wirklich von Endger&auml;t zu FHEM verschl&uuml;sselt wird und man sich nicht auf die Jabber Server Transportverschl&uuml;sselung verlassen muss.<br>
  1111. <br>
  1112. <br>
  1113. <a name="JabberDefine"></a>
  1114. <b>Define</b>
  1115. <ul>
  1116. <code>define &lt;name&gt; Jabber &lt;server&gt; &lt;port&gt; &lt;username&gt; &lt;password&gt; &lt;TLS&gt; &lt;SSL&gt;</code><br>
  1117. <br>
  1118. Du ben&ouml;tigst nat&uuml;rlich echte Accountdaten.<br>
  1119. <br>
  1120. Beispiel:
  1121. <ul>
  1122. <code>define JabberClient1 Jabber jabber.org 5222 myusername mypassword 1 0</code>
  1123. </ul>
  1124. <br>
  1125. </ul>
  1126. <br>
  1127. <a name="JabberSet"></a>
  1128. <b>Set</b>
  1129. <ul>
  1130. <li>
  1131. <code>set &lt;name&gt; msg &lt;username&gt; &lt;msg&gt;</code>
  1132. <br>
  1133. Sendet eine Nachricht "msg" an den Jabberuser "username"
  1134. <br>
  1135. Beispiel:
  1136. <ul>
  1137. <code>set JabberClient1 msg myname@jabber.org It is working!</code><br>
  1138. </ul>
  1139. </li>
  1140. <br>
  1141. <li>
  1142. <code>set &lt;name&gt; msgmuc &lt;channel&gt; &lt;msg&gt;</code>
  1143. <br>
  1144. Sendet eine Nachricht "msg" an dieJabber-MUC-Gruppe "channel".<br>
  1145. Dabei wird ein eventuell mitgegebener Nickname von "channel" entfernt, so kann man direkt das Reading LastMessageJID benutzen.<br>
  1146. <br>
  1147. Beispiel:
  1148. <ul>
  1149. <code>set JabberClient1 msgmuc roomname@jabber.org Woot!</code><br>
  1150. </ul>
  1151. </li>
  1152. <br>
  1153. <li>
  1154. <code>set &lt;name&gt; msgotr &lt;username&gt; &lt;msg&gt;</code>
  1155. <br>
  1156. Sendet eine OTR verschl&uuml;sselte Nachricht an den "username", wenn keine aktive OTR Sitzung aufgebaut ist, wird versucht eine aufzubauen.<br>
  1157. Wenn der Empf&auml;nger OTR nicht versteht, wird die Nachricht verworfen, d.h. sie wird auf keinen Fall im Klartext &uuml;bertragen.
  1158. <br>
  1159. Beispiel:
  1160. <ul>
  1161. <code>set JabberClient1 msgotr myname@jabber.org Wir sehen uns heute um 18:00 Uhr :*</code><br>
  1162. </ul>
  1163. </li>
  1164. <br>
  1165. <li>
  1166. <code>set &lt;name&gt; subscribe &lt;username&gt;</code>
  1167. <br>
  1168. Fr&auml;gt eine Authorisierung beim "username" an (normalerweise wird das nicht ben&ouml;tigt)
  1169. <br>
  1170. Beispiel:
  1171. <ul>
  1172. <code>set JabberClient1 subscribe myname@jabber.org</code><br>
  1173. </ul>
  1174. </li>
  1175. </ul>
  1176. <br>
  1177. <b>Get</b> <ul>N/A</ul><br>
  1178. <a name="JabberAttr"></a>
  1179. <b>Attribute</b>
  1180. <ul>
  1181. <a name="OnlineStatus"></a>
  1182. <li><code>OnlineStatus available|unavailable</code><br>
  1183. Setzt den Online-status, ob der Client anderen gegen&uuml;ber Online ist (available) oder Offline erscheint (unavailable)<br>
  1184. Es ist m&ouml;glich dass einige Server eingehende Nachrichten trotzdem FHEM zustellen obwohl er "unavailable" ist<br>
  1185. <br>
  1186. Standard: <code>available</code>
  1187. </li><br>
  1188. <a name="ResourceName"></a>
  1189. <li><code>ResourceName &lt;name&gt;</code><br>
  1190. In der Jabber-Welt kann ein Client mit einem Usernamen &ouml;fter mit einem Server verbunden sein (z.b. Handy, Computer, FHEM). <br>
  1191. Der "resource name" ergibt die finale Jabber-ID und macht die verschiedenen Verbindungen einzigartig (z.B. bios@jabber.org/FHEM).<br>
  1192. Hier kannst du den "resource name" setzen.<br>
  1193. <br>
  1194. Standard: <code>FHEM</code>
  1195. </li><br>
  1196. <a name="PollTimer"></a>
  1197. <li><code>PollTimer &lt;seconds&gt;</code><br>
  1198. Dies ist der Intervall in der &uuml;berpr&uuml;ft wird ob neue Nachrichten zur Verarbeitung beim Jabber Server anstehen.<br>
  1199. Ebenfalls wird hiermit die Verbindung zum Server &uuml;berpr&uuml;ft (Timeouts, DSL Disconnects etc.).<br>
  1200. Setze es nicht &uuml;ber 10 Sekunden, die Verbindung kann sonst die ganze Zeit getrennt werden, Sie wird zwar wieder aufgebaut, aber nach 10 Sekunden brechen die meisten Server die Verbindung automatisch ab.<br>
  1201. <br>
  1202. Standard: <code>2</code>
  1203. </li><br>
  1204. <a name="RecvWhitelist"></a>
  1205. <li><code>RecvWhitelist &lt;Regex&gt;</code><br>
  1206. Nur wenn die Jabber-ID einer privaten empfangenen Nachricht auf diese Regex zutrifft, akzeptiert FHEM die Nachricht und gibt sie an Notifys weiter. Alles andere wird verworfen.<br>
  1207. <br>
  1208. Standard: <code>.*</code><br>
  1209. Beispiele:<br>
  1210. <ul>
  1211. <code>myname@jabber.org</code><br>
  1212. <code>(myname1@jabber.org|myname2@xmpp.de)</code><br>
  1213. </ul>
  1214. </li><br>
  1215. <a name="MucJoin"></a>
  1216. <li><code>MucJoin channel1@server.com/mynick[:passwort]</code><br>
  1217. Tritt dem MUC mit dem spezifizierten Nickname und dem optionalem Passwort bei.<br>
  1218. <br>
  1219. Standard: nicht definiert<br>
  1220. Beispiele:<br>
  1221. <ul>
  1222. Einen Raum betreten: <code>channel1@server.com/mynick</code><br>
  1223. Mehrere R&auml;ume betreten: <code>channel1@server.com/mynick,channel2@server.com/myothernick</code><br>
  1224. Einen Raum mit Passwort betreten: <code>channel1@server.com/mynick:password</code><br>
  1225. </ul>
  1226. </li><br>
  1227. <a name="MucRecvWhitelist"></a>
  1228. <li><code>MucRecvWhitelist &lt;Regex&gt;</code><br>
  1229. Selbe funktion wie RecvWhitelist, aber f&uuml;r Gruppenr&auml;ume: Nur wenn die Regex zutrifft, wird die Nachricht verarbeitet. Alles andere wird ignoriert.<br>
  1230. <br>
  1231. Standard: nicht definiert (keine Nachricht wird akzeptiert)<br>
  1232. Beispiele:<br>
  1233. <ul>
  1234. Alle Nachrichten aller betretenen R&auml;ume erlauben: <code>.*</code><br>
  1235. Alle Nachrichten bestimmter betretenen R&auml;ume erlauben: <code>mychannel@jabber.org</code><br>
  1236. Nur bestimmte User in bestimmten betretenen R&auml;umen erlauben: <code>mychannel@jabber.org/NickOfFriend</code><br>
  1237. </ul>
  1238. </li><br>
  1239. <a name="OTREnable"></a>
  1240. <li><code>OTREnable 1|0</code><br>
  1241. Schaltet die Verschl&uuml;sselungsfunktionen von Crypt::OTR f&uuml;r sichere Ende-zu-Ende Kummunikation in FHEM an oder aus.<br>
  1242. Es muss zwangsl&auml;ufig daf&uuml;r Crypt::OTR installiert sein.<br>
  1243. <i>Ein Privater Schl&uuml;ssel wird bei Erstbenutzung generiert, das kann mehr als 2 Stunden dauern!</i><br>
  1244. Daf&uuml;r ist das eine einmalige Sache und FHEM wird dadurch nicht blockiert. Im Device sieht man im OTR_STATE wenn der Private Schl&uuml;ssel fertig ist.<br>
  1245. Erst danach ist OTR aktiv.<br>
  1246. <br>
  1247. Default: nicht definiert (OTR deaktiviert)
  1248. </li><br>
  1249. <a name="OTRSharedSecret"></a>
  1250. <li><code>OTRSharedSecret aSecretKeyiOnlyKnow@@*</code><br>
  1251. Optionales geheimes Passwort, dass man vom Endger&auml;t an FHEM schicken kann um zu beweisen, dass es sich tats&auml;chlich um FHEM handelt und nicht um einen
  1252. Hacker der sich (z.b. bei dem Internetprovider) zwischengeschaltet hat.
  1253. Normalerweise bekommt das Endger&auml;t eine Warnung wenn sich an einer bereits verifizierten Verbindung etwas ge&auml;ndert hat.<br>
  1254. Diese Warnung sollte man dann sehr ernst nehmen.
  1255. <br>
  1256. Default: nicht definiert, setze hier dein geheimes Passwort.
  1257. </li><br>
  1258. </ul>
  1259. <br>
  1260. <a name="JabberReadings"></a>
  1261. <b>Generierte Readings/Events:</b>
  1262. <ul>
  1263. <li>Privat Nachrichten
  1264. <ul>
  1265. <li><b>Message</b> - Komplette Nachricht inkl. JID und Text</li>
  1266. <li><b>LastMessage</b> - Nur der Textteil der Nachricht</li>
  1267. <li><b>LastSenderJID</b> - Nur die Sender-JID der Nachricht</li>
  1268. </ul>
  1269. </li><br>
  1270. <li>Verschl&uuml;sselte Private Nachrichten (wenn OTREnable=1)
  1271. <ul>
  1272. <li><b>OTRMessage</b> - Komplette entschl&uuml;sselte Nachricht inkl. JID und Text</li>
  1273. <li><b>OTRLastMessage</b> - Nur der Textteil der Nachricht</li>
  1274. <li><b>OTRLastSenderJID</b> - Nur die Sender-JID der Nachricht</li>
  1275. </ul>
  1276. </li><br>
  1277. <li>MUC Raum Nachrichten (wenn MUCJoin gesetzt ist)
  1278. <ul>
  1279. <li><b>MucMessage</b> - Komplette Nachricht (Raumname/Nickname und Text)</li>
  1280. <li><b>MucLastMessage</b> - Nur der Textteil der Nachricht</li>
  1281. <li><b>MucLastSenderJID</b> - Nur die Sender-JID der Nachricht</li>
  1282. </ul>
  1283. </li>
  1284. </ul>
  1285. <br>
  1286. <a name="JabberNotes"></a>
  1287. <b>Notizen des Entwicklers:</b>
  1288. <ul>
  1289. <li>Mit folgendem Notify-Beispiel kannst du auf eingehende Nachrichten reagieren, dieses Beispiel schickt das Reading "Temperatur" des Sensors "BU_Temperatur" bei jeder ankommenden Nachricht an den Sender zur&uuml;ck:<br>
  1290. <pre><code>define Jabber_Notify notify JabberClient1:Message.* {
  1291. my $lastsender=ReadingsVal("JabberClient1","LastSenderJID","0");
  1292. my $lastmsg=ReadingsVal("JabberClient1","LastMessage","0");
  1293. my $temperature=ReadingsVal("BU_Temperatur","temperature","0");
  1294. fhem("set JabberClient1 msg ". $lastsender . " Temp: ".$temperature);
  1295. }
  1296. </code></pre>
  1297. </li>
  1298. <li>Auf MUC Nachrichten l&auml;sst sich folgend reagieren, Augenmerk darauf legen dass der Nickname aus $lastsender in der msgmuc Funktion entfernt wird, damit die Nachricht an den Raum geht<br>
  1299. <pre><code>define Jabber_Notify notify JabberClient1:MucMessage.* {
  1300. my $lastsender=ReadingsVal("JabberClient1","LastSenderJID","0");
  1301. my $lastmsg=ReadingsVal("JabberClient1","LastMessage","0");
  1302. my $temperature=ReadingsVal("BU_Temperatur","temperature","0");
  1303. fhem("set JabberClient1 msgmuc ". $lastsender . " Temp: ".$temperature);
  1304. }
  1305. </code></pre>
  1306. </li>
  1307. <li>Auf OTR Nachrichten wird reagiert, wie auf normale private Nachrichten auch, jedoch wird mit der msgotr Funktion geantwortet:<br>
  1308. <pre><code>define Jabber_Notify notify JabberClient1:OTRMessage.* {
  1309. my $lastsender=ReadingsVal("JabberClient1","LastSenderJID","0");
  1310. my $lastmsg=ReadingsVal("JabberClient1","LastMessage","0");
  1311. my $temperature=ReadingsVal("BU_Temperatur","temperature","0");
  1312. fhem("set JabberClient1 msgotr ". $lastsender . " Temp: ".$temperature);
  1313. }
  1314. </code></pre>
  1315. </li>
  1316. </ul>
  1317. </ul>
  1318. =end html_DE
  1319. =cut