source: perl/modules/jabber.pl @ 960395d

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