source: perl/modules/jabber.pl @ 6a6dd47

barnowl_perlaimdebianrelease-1.10release-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since 6a6dd47 was 6a6dd47, checked in by Alejandro R. Sedeño <asedeno@mit.edu>, 19 years ago
jabber.pl: * Multiple connections now possible. * Password-based authentication now possible. * jabberlogin now requires a login jid. * jabberlogin now uses _xmpp-client._tcp srv record for lookup. If no record exists, server part of jid is used with port 5222. * Eliminated various globals. Current globals are: $connections -> Holds all the client and roster objects, indexed by full jid. $connections->{JID}->{client} $connections->{JID}->{roster} %vars -> used to pass data around between functions and related callbacks. * New dependences: Getopt::Long, Net::DNS README: added a readme. It probably wants more in it.
  • Property mode set to 100644
File size: 19.3 KB
RevLine 
[38ffdf9]1package owl_jabber;
2use Authen::SASL qw(Perl);
3use Net::Jabber;
[6a6dd47]4use Net::DNS;
5use Getopt::Long;
6
[38ffdf9]7################################################################################
8# owl perl jabber support
9#
[b6a253c]10# XXX Todo:
11# Rosters for MUCs
12# More user feedback
13#  * joining MUC
14#  * parting MUC
15#  * presence (Roster and MUC)
16# Implementing formatting and logging callbacks for C
17# Appropriate callbacks for presence subscription messages.
18#  * Current behavior => auto-accept (default for Net::Jabber)
[38ffdf9]19#
20################################################################################
21
[6a6dd47]22our $connections;
23our %vars;
[38ffdf9]24
25sub onStart
26{
27    if(eval{\&owl::queue_message}) 
28    {
29        register_owl_commands();
[b6a253c]30        push @::onMainLoop, sub { owl_jabber::onMainLoop(@_) };
31        push @::onGetBuddyList, sub { owl_jabber::onGetBuddyList(@_) };
[38ffdf9]32    }
33    else
34    {
35        # Our owl doesn't support queue_message. Unfortunately, this
36        # means it probably *also* doesn't support owl::error. So just
37        # give up silently.
38    }
39}
[b6a253c]40push @::onStartSubs, sub { owl_jabber::onStart(@_) };
[38ffdf9]41
42sub onMainLoop
43{
[6a6dd47]44    return if (!connected());
[38ffdf9]45   
[6a6dd47]46    foreach my $jid (keys %$connections)
[38ffdf9]47    {
[6a6dd47]48        my $client = \$connections->{$jid}->{client};
49
50        my $status = $$client->Process(0);
51        if ($status == 0     # No data received
52        || $status == 1) # Data received
53        {
54        }
55        else #Error
56        {
57            do_logout($jid);
58            return;
59        }
60       
61        if ($::shutdown)
62        {
63            do_logout($jid);
64            return;
65        }
[38ffdf9]66    }
67}
[b6a253c]68
69sub blist_listBuddy
70{
[6a6dd47]71    my $roster = shift;
[b6a253c]72    my $buddy = shift;
73    my $blistStr .= "    ";
[6a6dd47]74    my %jq = $$roster->query($buddy);
75    my $res = $$roster->resource($buddy);
[b6a253c]76
77    $blistStr .= $jq{name} ? $jq{name} : $buddy->GetJID();
78   
79    if ($res)
80    {
[6a6dd47]81        my %rq = $$roster->resourceQuery($buddy, $res);
[b6a253c]82        $blistStr .= " [".($rq{show} ? $rq{show} : 'online')."]";
83        $blistStr .= " ".$rq{status} if $rq{status};
84        $blistStr = boldify($blistStr);
85    }
86    else
87    {
88        $blistStr .= $jq{ask} ? " [pending]" : " [offline]";
89    }
90
91    return $blistStr."\n";
92}
93
94sub onGetBuddyList
95{
[6a6dd47]96    my $blist = "";
97    foreach my $jid (keys %{$connections})
[b6a253c]98    {
[6a6dd47]99        my $roster = \$connections->{$jid}->{roster};
100        if ($$roster)
[b6a253c]101        {
[6a6dd47]102            $blist .= "\n".boldify("Jabber Roster for $jid\n");
103           
104            foreach my $group ($$roster->groups())
105            {
106                $blist .= "  Group: $group\n";
107                foreach my $buddy ($$roster->jids('group',$group))
108                {
109                    $blist .= blist_listBuddy($roster, $buddy);
110                }
111            }
112           
113            my @unsorted = $$roster->jids('nogroup');
114            if (@unsorted)
115            {
116                $blist .= "  [unsorted]\n";
117                foreach my $buddy (@unsorted)
118                {
119                    $blist .= blist_listBuddy($roster, $buddy);
120                }
121            }
[b6a253c]122        }
123    }
[6a6dd47]124    return $blist;
[b6a253c]125}
[38ffdf9]126
127################################################################################
128### Owl Commands
129sub register_owl_commands()
130{
131    owl::new_command(
132        jabberlogin => \&cmd_login,
133        { summary => "Log into jabber", }
134    );
135    owl::new_command(
136        jabberlogout => \&cmd_logout,
137        { summary => "Log out of jabber" }
138    );
139    owl::new_command(
140        jwrite => \&cmd_jwrite,
141        {
142            summary     => "Send a Jabber Message",
[b6a253c]143            usage       => "jwrite JID [-g] [-t thread] [-s subject]"
[38ffdf9]144        }
145    );
146    owl::new_command(
[b6a253c]147        jlist => \&cmd_jlist,
[38ffdf9]148        {
[b6a253c]149            summary     => "Show your Jabber roster.",
150            usage       => "jlist"
[38ffdf9]151        }
152    );
153    owl::new_command(
[b6a253c]154        jmuc => \&cmd_jmuc,
[38ffdf9]155        {
[b6a253c]156            summary     => "Jabber MUC related commands.",
157            description => "jmuc sends jabber commands related to muc.\n\n".
158                "The following commands are available\n\n".
159                "join {muc}  Join a muc.\n\n".
160                "part [muc]  Part a muc.".
161                "            The muc is taken from the current message if not supplied.\n\n".
162                "invite {jid} [muc]\n\n".
163                "            Invite {jid} to [muc].\n".
164                "            The muc is taken from the current message if not supplied.\n\n",
165            usage       => "jmuc {command} {args}"
[38ffdf9]166        }
167    );
168}
169
170sub cmd_login
171{
[6a6dd47]172    my $cmd = shift;
173    my $jid = new Net::XMPP::JID;
174    $jid->SetJID(shift);
175   
176    my $uid = $jid->GetUserID();
177    my $componentname = $jid->GetServer();
178    my $resource = $jid->GetResource() || 'owl';
179    $jid->SetResource($resource);
180    my $jidStr = $jid->GetJID('full');
181
182    if (!$uid || !$componentname)
[38ffdf9]183    {
[6a6dd47]184        owl::error("usage: $cmd {jid}");
[38ffdf9]185        return;
186    }
[b6a253c]187
[6a6dd47]188    if ($connections->{$jidStr})
189    {
190        owl::error("Already logged in as $jidStr.");
191        return;
192    }
193
194    my ($server, $port) = getServerFromJID($jid);
195
196    $connections->{$jidStr}->{client} = Net::Jabber::Client->new();
197    my $client = \$connections->{$jidStr}->{client};
198    $connections->{$jidStr}->{roster} = $connections->{$jidStr}->{client}->Roster();
[b6a253c]199
200    #XXX Todo: Add more callbacks.
201    # MUC presence handlers
[6a6dd47]202    $$client->SetMessageCallBacks(chat => sub { owl_jabber::process_incoming_chat_message(@_) },
203                                  error => sub { owl_jabber::process_incoming_error_message(@_) },
204                                  groupchat => sub { owl_jabber::process_incoming_groupchat_message(@_) },
205                                  headline => sub { owl_jabber::process_incoming_headline_message(@_) },
206                                  normal => sub { owl_jabber::process_incoming_normal_message(@_) });
207
208    $vars{jlogin_connhash} = {hostname => $server,
209                          tls => 1,
210                          port => $port,
211                          componentname => $componentname};
212
213    my $status = $$client->Connect(%{$vars{jlogin_connhash}});
214
[38ffdf9]215    if (!$status)
216    {
[6a6dd47]217        delete $connections->{$jidStr};
218        delete $vars{jlogin_connhash};
[38ffdf9]219        owl::error("We failed to connect");
[6a6dd47]220        return "";
[38ffdf9]221    }
222
[b6a253c]223
[6a6dd47]224    $vars{jlogin_authhash} = {username => $uid, resource => $resource, password => ''};
225    my @result = $$client->AuthSend(%{$vars{jlogin_authhash}});
226    if($result[0] ne 'ok') 
227    {
228        if ($result[1] = "401")
229        {
230            $vars{jlogin_jid} = $jidStr;
231            delete $connections->{$jidStr};
232            owl::start_password("Password for $jidStr: ", \&do_login_with_pw);
233            return "";
234        }
[38ffdf9]235        owl::error("Error in connect: " . join(" ", $result[1..$#result]));
[6a6dd47]236        do_logout($jidStr);
237        delete $vars{jlogin_connhash};
238        delete $vars{jlogin_authhash};
239        return "";
[38ffdf9]240    }
[6a6dd47]241    $connections->{$jidStr}->{roster}->fetch();
242    $$client->PresenceSend(priority => 1);
243    queue_admin_msg("Connected to jabber as $jidStr");
244    delete $vars{jlogin_connhash};
245    delete $vars{jlogin_authhash};
246    return "";
247}
[38ffdf9]248
[6a6dd47]249sub do_login_with_pw
250{
251    $vars{jlogin_authhash}->{password} = shift;
252    my $jidStr = delete $vars{jlogin_jid};
253    if (!$jidStr)
254    {
255        owl::error("Got password but have no jid!");
256    }
257
258    $connections->{$jidStr}->{client} = Net::Jabber::Client->new();
259    my $client = \$connections->{$jidStr}->{client};
260    $connections->{$jidStr}->{roster} = $connections->{$jidStr}->{client}->Roster();
261
262    $$client->SetMessageCallBacks(chat => sub { owl_jabber::process_incoming_chat_message(@_) },
263                                  error => sub { owl_jabber::process_incoming_error_message(@_) },
264                                  groupchat => sub { owl_jabber::process_incoming_groupchat_message(@_) },
265                                  headline => sub { owl_jabber::process_incoming_headline_message(@_) },
266                                  normal => sub { owl_jabber::process_incoming_normal_message(@_) });
[38ffdf9]267
[6a6dd47]268    my $status = $$client->Connect(%{$vars{jlogin_connhash}});
269    if (!$status)
270    {
271        delete $connections->{$jidStr};
272        delete $vars{jlogin_connhash};
273        delete $vars{jlogin_authhash};
274        owl::error("We failed to connect");
275        return "";
276    }
277
278    my @result = $$client->AuthSend(%{$vars{jlogin_authhash}});
279
280    if($result[0] ne 'ok') 
281    {
282        owl::error("Error in connect: " . join(" ", $result[1..$#result]));
283        do_logout($jidStr);
284        delete $vars{jlogin_connhash};
285        delete $vars{jlogin_authhash};
286        return "";
287    }
288
289    $connections->{$jidStr}->{roster}->fetch();
290    $$client->PresenceSend(priority => 1);
291    queue_admin_msg("Connected to jabber as $jidStr");
292    delete $vars{jlogin_connhash};
293    delete $vars{jlogin_authhash};
[38ffdf9]294    return "";
295}
296
[6a6dd47]297sub do_logout
298{
299    my $jid = shift;
300    $connections->{$jid}->{client}->Disconnect();
301    delete $connections->{$jid};
302    queue_admin_msg("Jabber disconnected ($jid).");
303}
304
[38ffdf9]305sub cmd_logout
306{
[6a6dd47]307    # Logged into multiple accounts
308    if (connected() > 1)
[38ffdf9]309    {
[6a6dd47]310        # Logged into multiple accounts, no accout specified.
311        if (!$_[1])
312        {
313            my $errStr = "You are logged into multiple accounts. Please specify an account to log out of.\n";
314            foreach my $jid (keys %$connections)
315            {
316                $errStr .= "\t$jid\n";
317            }
318            queue_admin_msg($errStr);
319        }
320        # Logged into multiple accounts, account specified.
321        else
322        {
323            if ($_[1] = '-a') #All accounts.
324            {
325                foreach my $jid (keys %$connections)
326                {
327                    do_logout($jid);
328                }
329            }
330            else #One account.
331            {
332                my $jid = resolveJID($_[1]);
333                do_logout($jid) if ($jid ne '');
334            }
335        }
336    }
337    else # Only one account logged in.
338    {
339       
340        do_logout((keys %$connections)[0]);
[38ffdf9]341    }
342    return "";
343}
344
[b6a253c]345sub cmd_jlist
346{
[6a6dd47]347    if (!(scalar keys %$connections))
[b6a253c]348    {
349        owl::error("You are not logged in to Jabber.");
350        return;
351    }
352    owl::popless_ztext(onGetBuddyList());
353}
354
[38ffdf9]355sub cmd_jwrite
356{
[6a6dd47]357    if (!connected())
[38ffdf9]358    {
[b6a253c]359        owl::error("You are not logged in to Jabber.");
[38ffdf9]360        return;
361    }
362
[6a6dd47]363    my $jwrite_to = "";
364    my $jwrite_from = "";
365    my $jwrite_thread = "";
366    my $jwrite_subject = "";
367    my $jwrite_type = "chat";
[38ffdf9]368
[6a6dd47]369    my @args = @_;
370    shift;
371    local @::ARGV = @_;
372    my $gc;
373    GetOptions('thread=s' => \$jwrite_thread,
374               'subject=s' => \$jwrite_subject,
375               'account=s' => \$jwrite_from,
376               'groupchat' => \$gc);
377    $jwrite_type = 'groupchat' if $gc;
378
379    if (scalar @::ARGV != 1)
380    {
381        owl::error("Usage: jwrite JID [-g] [-t thread] [-s 'subject'] [-a account]");
382        return;
383    }
384    else
[38ffdf9]385    {
[6a6dd47]386        $jwrite_to = @::ARGV[0];
387    }
[b6a253c]388
[6a6dd47]389    if (!$jwrite_from)
390    {
391        if (connected() == 1)
[38ffdf9]392        {
[6a6dd47]393            $jwrite_from = (keys %$connections)[0];
[38ffdf9]394        }
[6a6dd47]395        else
[38ffdf9]396        {
[6a6dd47]397            owl::error("Please specify an account with -a {jid}");
398            return;
[38ffdf9]399        }
400    }
[6a6dd47]401    else
[b6a253c]402    {
[6a6dd47]403        $jwrite_from = resolveJID($jwrite_from);
404        return unless $jwrite_from;
[38ffdf9]405    }
[6a6dd47]406   
407    $vars{jwrite} = {to => $jwrite_to, 
408                     from => $jwrite_from,
409                     subject => $jwrite_subject,
410                     thread => $jwrite_thread,
411                     type => $jwrite_type};
[b6a253c]412
[38ffdf9]413    owl::message("Type your message below.  End with a dot on a line by itself.  ^C will quit.");
414    owl::start_edit_win(join(' ', @args), \&process_owl_jwrite);
415}
416
[6a6dd47]417#XXX Todo: Split off sub-commands into their own subroutines.
418# It'll make them more managable.
[b6a253c]419sub cmd_jmuc
[38ffdf9]420{
[6a6dd47]421    if (!connected())
[38ffdf9]422    {
[b6a253c]423        owl::error("You are not logged in to Jabber.");
[38ffdf9]424        return;
425    }
[b6a253c]426   
[6a6dd47]427    my $ocmd = shift;
428    my $cmd = shift;   
429    if (!$cmd)
[38ffdf9]430    {
[b6a253c]431        #XXX TODO: Write general usage for jmuc command.
[38ffdf9]432        return;
433    }
434
[b6a253c]435    if ($cmd eq 'join')
436    {
[6a6dd47]437        local @::ARGV = @_;
438        my $password;
439        my $jid;
440        GetOptions('password=s' => \$password,
441                   'account=s' => \$jid);
442
443        my $muc;
444        if (scalar @::ARGV != 1)
[b6a253c]445        {
[6a6dd47]446            owl::error('Usage: jmuc join {muc} [-p password] [-a account]');
[b6a253c]447            return;
448        }
[6a6dd47]449        else
450        {
451            $muc = @::ARGV[0];
452        }
453
454        if (!$jid)
455        {
456            if (connected() == 1)
457            {
458                $jid = (keys %$connections)[0];
459            }
460            else
461            {
462                owl::error("Please specify an account with -a {jid}");
463                return;
464            }
465        }
466        else
467        {
468            $jid = resolveJID($jid);
469            return unless $jid;
470        }
471
[b6a253c]472        my $x = new XML::Stream::Node('x');
473        $x->put_attrib(xmlns => 'http://jabber.org/protocol/muc');
474        $x->add_child('history')->put_attrib(maxchars => '0');
475       
[6a6dd47]476        if ($jmuc_password)
[b6a253c]477        {
[6a6dd47]478            $x->add_child('password')->add_cdata($jmuc_password);
[b6a253c]479        }
[38ffdf9]480
[b6a253c]481        my $presence = new Net::Jabber::Presence;
482        $presence->SetPresence(to => $muc);
483        $presence->AddX($x);
[6a6dd47]484        $connections->{$jid}->{client}->Send($presence);
[b6a253c]485    }
486    elsif ($cmd eq 'part')
[38ffdf9]487    {
[b6a253c]488        my $muc;
[6a6dd47]489        my $jid;
490        if (!$_[0])
[b6a253c]491        {
492            my $m = owl::getcurmsg();
493            if ($m->is_jabber && $m->{jtype} eq 'groupchat')
494            {
[6a6dd47]495                $muc = $m->{room};
496                $jid = $m->{to};
[b6a253c]497            }
498            else
499            {
[6a6dd47]500                owl::error('Usage: jmuc part {muc} [-a account]');
[b6a253c]501                return;
502            }
503        }
504        else
505        {
[6a6dd47]506            local @::ARGV = @_;
507            GetOptions('account=s' => \$jid);
508            if (scalar @::ARGV != 1)
509            {
510                owl::error('Usage: jmuc part {muc} [-a account]');
511                return;
512            }
513            else
514            {
515                $muc = @::ARGV[0];
516            }
517            if (!$jid)
518            {
519                if (connected() == 1)
520                {
521                    $jid = (keys %$connections)[0];
522                }
523                else
524                {
525                    owl::error("Please specify an account with -a {jid}");
526                    return;
527                }
528            }
529            else
530            {
531                $jid = resolveJID($jid);
532                return unless $jid;
533            }
[b6a253c]534        }
[6a6dd47]535        $connections->{$jid}->{client}->PresenceSend(to => $muc, type => 'unavailable');
536        queue_admin_msg("$jid has left $muc.");
[38ffdf9]537    }
[b6a253c]538    elsif ($cmd eq 'invite')
[38ffdf9]539    {
[b6a253c]540        my $jid;
[6a6dd47]541        my $invite_jid;
[b6a253c]542        my $muc;
543
[6a6dd47]544        owl::error('Usage: jmuc invite {jid} [muc] [-a account]') if (!$_[0]);
545        $invite_jid = $_[0];
[b6a253c]546       
[6a6dd47]547        if (!@_[1])
[b6a253c]548        {       
549            my $m = owl::getcurmsg();
550            if ($m->is_jabber && $m->{jtype} eq 'groupchat')
551            {
[6a6dd47]552                $muc = $m->{room};
553                $jid = $m->{to};
[b6a253c]554            }
555            else
556            {
[6a6dd47]557                owl::error('Usage: jmuc invite {jid} [muc] [-a account]');
[b6a253c]558                return;
559            }
560        }
561        else
562        {
[6a6dd47]563            local @::ARGV = @_;
564            GetOptions('account=s' => \$jid);
565            if (scalar @::ARGV != 2)
566            {
567                owl::error('Usage: jmuc invite {jid} [muc] [-a account]');
568                return;
569            }
570            else
571            {
572                ($muc, $invite_jid) = @::ARGV;
573            }
574            if (!$jid)
575            {
576                if (connected() == 1)
577                {
578                    $jid = (keys %$connections)[0];
579                }
580                else
581                {
582                    owl::error("Please specify an account with -a {jid}");
583                    return;
584                }
585            }
586            else
587            {
588                $jid = resolveJID($jid);
589                return unless $jid;
590            }
[b6a253c]591        }
592       
593        my $x = new XML::Stream::Node('x');
594        $x->put_attrib(xmlns => 'http://jabber.org/protocol/muc#user');
[6a6dd47]595        $x->add_child('invite')->put_attrib(to => $invite_jid);
[b6a253c]596       
597        my $message = new Net::Jabber::Message;
598        $message->SetTo($muc);
599        $message->AddX($x);
[6a6dd47]600        $connections->{$jid}->{client}->Send($message);
601        queue_admin_msg("$jid has invited $invite_jid to $muc.");
[38ffdf9]602    }
[b6a253c]603    else
[38ffdf9]604    {
[b6a253c]605        owl::error('jmuc: unrecognized command.');
[38ffdf9]606    }
[b6a253c]607    return "";
[38ffdf9]608}
609
610################################################################################
611### Owl Callbacks
612sub process_owl_jwrite
613{
614    my $body = shift;
615
616    my $j = new Net::XMPP::Message;
617    $body =~ s/\n\z//;
[6a6dd47]618    $j->SetMessage(to => $vars{jwrite}{to},
619                   from => $vars{jwrite}{from},
620                   type => $vars{jwrite}{type},
[38ffdf9]621                   body => $body
622                   );
[6a6dd47]623    $j->SetThread($vars{jwrite}{thread}) if ($vars{jwrite}{thread});
624    $j->SetSubject($vars{jwrite}{subject}) if ($vars{jwrite}{subject});
625   
[38ffdf9]626    my $m = j2o($j, 'out');
[6a6dd47]627    if ($vars{jwrite}{type} ne 'groupchat')
[38ffdf9]628    {
629        #XXX TODO: Check for displayoutgoing.
630        owl::queue_message($m);
631    }
[6a6dd47]632    $connections->{$vars{jwrite}{from}}->{client}->Send($j);
633    delete $vars{jwrite};
[38ffdf9]634}
635
636### XMPP Callbacks
637
638sub process_incoming_chat_message
639{
640    my ($session, $j) = @_;
641    owl::queue_message(j2o($j, 'in'));
642}
643
644sub process_incoming_error_message
645{
646    my ($session, $j) = @_;
[b6a253c]647    my %jhash = j2hash($j, 'in');
648    $jhash{type} = 'admin';
649    owl::queue_message(owl::Message->new(%jhash));
[38ffdf9]650}
651
652sub process_incoming_groupchat_message
653{
654    my ($session, $j) = @_;
655    # HACK IN PROGRESS (ignoring delayed messages)
656    return if ($j->DefinedX('jabber:x:delay') && $j->GetX('jabber:x:delay'));
657    owl::queue_message(j2o($j, 'in'));
658}
659
660sub process_incoming_headline_message
661{
662    my ($session, $j) = @_;
663    owl::queue_message(j2o($j, 'in'));
664}
665
666sub process_incoming_normal_message
667{
668    my ($session, $j) = @_;
[b6a253c]669    my %props = j2hash($j, 'in');
670
671    # XXX TODO: handle things such as MUC invites here.
672
673#    if ($j->HasX('http://jabber.org/protocol/muc#user'))
674#    {
675#       my $x = $j->GetX('http://jabber.org/protocol/muc#user');
676#       if ($x->HasChild('invite'))
677#       {
678#           $props         
679#       }
680#    }
681#   
682    owl::queue_message(owl::Message->new(%props));
683}
684
685sub process_muc_presence
686{
687    my ($session, $p) = @_;
688    return unless ($p->HasX('http://jabber.org/protocol/muc#user'));
689   
[38ffdf9]690}
691
692
693### Helper functions
694
[b6a253c]695sub j2hash
[38ffdf9]696{
697    my $j = shift;
698    my $dir = shift;
699
700    my %props = (type => 'jabber',
701                 direction => $dir);
702
[b6a253c]703    my $jtype = $props{jtype} = $j->GetType();
704    my $from  = $j->GetFrom('jid');
705    my $to    = $j->GetTo('jid');
[38ffdf9]706
[b6a253c]707    $props{from} = $from->GetJID('full');
708    $props{to}   = $to->GetJID('full');
[38ffdf9]709
[b6a253c]710    $props{recipient}  = $to->GetJID('base');
711    $props{sender}     = $from->GetJID('base');
712    $props{subject}    = $j->GetSubject() if ($j->DefinedSubject());
713    $props{thread}     = $j->GetThread() if ($j->DefinedThread());
714    $props{body}       = $j->GetBody() if ($j->DefinedBody());
715    $props{error}      = $j->GetError() if ($j->DefinedError());
716    $props{error_code} = $j->GetErrorCode() if ($j->DefinedErrorCode());
717    $props{xml}        = $j->GetXML();
[38ffdf9]718
[b6a253c]719    if ($jtype eq 'chat')
[38ffdf9]720    {
[b6a253c]721        $props{replycmd} = "jwrite ".(($dir eq 'in') ? $props{from} : $props{to});
[6a6dd47]722        $props{replycmd} .= " -a ".(($dir eq 'out') ? $props{from} : $props{to});
[b6a253c]723        $props{isprivate} = 1;
[38ffdf9]724    }
[b6a253c]725    elsif ($jtype eq 'groupchat')
[38ffdf9]726    {
[b6a253c]727        my $nick = $props{nick} = $from->GetResource();
728        my $room = $props{room} = $from->GetJID('base');
729        $props{replycmd} = "jwrite -g $room";
[6a6dd47]730        $props{replycmd} .= " -a ".(($dir eq 'out') ? $props{from} : $props{to});
[b6a253c]731       
[6a6dd47]732        $props{sender} = $nick || $room;
[b6a253c]733        $props{recipient} = $room;
734
735        if ($props{subject} && !$props{body})
[38ffdf9]736        {
[b6a253c]737            $props{body} = '['.$nick." has set the topic to: ".$props{subject}."]"
[38ffdf9]738        }
739    }
[b6a253c]740    elsif ($jtype eq 'normal')
741    {
742        $props{replycmd} = undef;
743        $props{isprivate} = 1;
744    }
745    elsif ($jtype eq 'headline')
746    {
747        $props{replycmd} = undef;
748    }
749    elsif ($jtype eq 'error')
750    {
751        $props{replycmd} = undef;
752        $props{body} = "Error ".$props{error_code}." sending to ".$props{from}."\n".$props{error};
753    }
754   
[38ffdf9]755    $props{replysendercmd} = $props{replycmd};
[b6a253c]756    return %props;
757}
[38ffdf9]758
[b6a253c]759sub j2o
760{
761    return owl::Message->new(j2hash(@_));
[38ffdf9]762}
763
764sub queue_admin_msg
765{
766    my $err = shift;
767    my $m = owl::Message->new(type => 'admin',
768                              direction => 'none',
769                              body => $err);
770    owl::queue_message($m);
771}
[b6a253c]772
773sub boldify($)
774{
775    $str = shift;
776
777    return '@b('.$str.')' if ( $str !~ /\)/ );
778    return '@b<'.$str.'>' if ( $str !~ /\>/ );
779    return '@b{'.$str.'}' if ( $str !~ /\}/ );
780    return '@b['.$str.']' if ( $str !~ /\]/ );
781
782    my $txt = "\@b($str";
783    $txt =~ s/\)/\)\@b\[\)\]\@b\(/g;
784    return $txt.')';
785}
786
[6a6dd47]787sub getServerFromJID
788{
789    my $jid = shift;
790    my $res = new Net::DNS::Resolver;
791    my $packet = $res->search('_xmpp-client._tcp.'.$jid->GetServer(), 'srv');
792
793    if ($packet) # Got srv record.
794    {
795        my @answer = $packet->answer;
796        return $answer[0]{target},
797                $answer[0]{port};
798    }
799
800    return $jid->GetServer(), 5222;
801}
802
803sub connected
804{
805    return scalar keys %$connections;
806}
807
808sub resolveJID
809{
810    my $givenJidStr = shift;
811    my $givenJid = new Net::XMPP::JID;
812    $givenJid->SetJID($givenJidStr);
813   
814    # Account fully specified.
815    if ($givenJid->GetResource())
816    {
817        # Specified account exists
818        if (defined $connections->{$givenJidStr})
819        {
820            return $givenJidStr;
821        }
822        else #Specified account doesn't exist
823        {
824            owl::error("Invalid account: $givenJidStr");
825        }
826    }
827    # Disambiguate.
828    else
829    {
830        my $matchingJid = "";
831        my $errStr = "Ambiguous account reference. Please specify a resource.\n";
832        my $ambiguous = 0;
833       
834        foreach my $jid (keys %$connections)
835        {
836            my $cJid = new Net::XMPP::JID;
837            $cJid->SetJID($jid);
838            if ($givenJidStr eq $cJid->GetJID('base'))
839            {
840                $ambiguous = 1 if ($matchingJid ne "");
841                $matchingJid = $jid;
842                $errStr .= "\t$jid\n";
843            }
844        }
845        # Need further disambiguation.
846        if ($ambiguous)
847        {
848            queue_admin_msg($errStr);
849        }
850        # Not one of ours.
851        elsif ($matchingJid eq "")
852        {
853            owl::error("Invalid account: $givenJidStr");
854          }
855        # Log out this one.
856        else
857        {
858            return $matchingJid;
859        }
860    }
861    return "";
862}
Note: See TracBrowser for help on using the repository browser.