File Coverage

blib/lib/Net/Lyskom.pm
Criterion Covered Total %
statement 192 673 28.5
branch 24 230 10.4
condition 5 16 31.2
subroutine 42 120 35.0
pod 85 89 95.5
total 348 1128 30.8


line stmt bran cond sub pod time code
1             package Net::Lyskom;
2              
3 1     1   84844 use 5.8.3;
  1         3  
  1         53  
4              
5 1     1   7 use base qw{Net::Lyskom::Object};
  1         2  
  1         680  
6              
7 1     1   7 use strict;
  1         2  
  1         31  
8 1     1   1065 use IO::Socket;
  1         32023  
  1         6  
9 1     1   1928 use Time::Local;
  1         2032  
  1         67  
10 1     1   4266 use Encode;
  1         12621  
  1         143  
11 1     1   542 use Net::Lyskom::AuxItem;
  1         3  
  1         30  
12 1     1   576 use Net::Lyskom::MiscInfo;
  1         3  
  1         27  
13 1     1   490 use Net::Lyskom::Time;
  1         6  
  1         26  
14 1     1   660 use Net::Lyskom::TextStat;
  1         3  
  1         33  
15 1     1   655 use Net::Lyskom::Conference;
  1         2  
  1         28  
16 1     1   623 use Net::Lyskom::Person;
  1         3  
  1         36  
17 1     1   7 use Net::Lyskom::Util qw(:all);
  1         2  
  1         149  
18 1     1   679 use Net::Lyskom::Membership;
  1         3  
  1         38  
19 1     1   643 use Net::Lyskom::TextMapping;
  1         4  
  1         26  
20 1     1   603 use Net::Lyskom::ConfZInfo;
  1         3  
  1         27  
21 1     1   559 use Net::Lyskom::DynamicSession;
  1         2  
  1         28  
22 1     1   632 use Net::Lyskom::StaticSession;
  1         3  
  1         29  
23 1     1   652 use Net::Lyskom::Member;
  1         3  
  1         25  
24 1     1   758 use Net::Lyskom::Info;
  1         3  
  1         27  
25              
26 1     1   6 use Carp;
  1         3  
  1         72  
27              
28 1     1   7 use vars qw{ @error };
  1         1  
  1         8267  
29              
30              
31             our $VERSION = '1.2';
32              
33             =head1 NAME
34              
35             Net::Lyskom - Perl module used to talk to LysKOM servers.
36              
37             =head1 SYNOPSIS
38              
39             use Net::Lyskom;
40              
41             $a = Net::Lyskom->new();
42             $conf = 6;
43              
44             $a->login(pers_no => 437, password => "God", invisible => 1)
45             or die "Failed to log in: $a->err_string\n";
46              
47             $b = $a->send_message(7680, "Oook!");
48              
49             $b = $a->create_text(
50             subject => "Testsubject",
51             body => "A nice and tidy message body.",
52             recpt => [437],
53             );
54              
55             if ($b) {
56             print "Text number $b created.\n";
57             } else {
58             print "Text creation failed: $a->err_string.\n";
59             }
60              
61             =head1 DESCRIPTION
62              
63             Net::Lyskom is a module used to talk to LysKOM servers. This far
64             it lacks a lot of functions, but there are enough functions implemented
65             to program statistics robots and such.
66              
67             =head2 Metoder
68              
69             =over
70              
71             =cut
72              
73             ## Variables
74              
75              
76             @error = qw(no-error
77             unused
78             not-implemented
79             obsolete-call
80             invalid-password
81             string-too-long
82             login-first
83             login-disallowed
84             conference-zero
85             undefined-conference
86             undefined-person
87             access-denied
88             permission-denied
89             not-member
90             no-such-text
91             text-zero
92             no-such-local-text
93             local-text-zero
94             bad-name
95             index-out-of-range
96             conference-exists
97             person-exists
98             secret-public
99             letterbox
100             ldb-error
101             illegal-misc
102             illegal-info-type
103             already-recipient
104             already-comment
105             already-footnote
106             not-recipient
107             not-comment
108             not-footnote
109             recipient-limit
110             comment-limit
111             footnote-limit
112             mark-limit
113             not-author
114             no-connect
115             out-of-memory
116             server-is-crazy
117             client-is-crazy
118             undefined-session
119             regexp-error
120             not-marked
121             temporary-failure
122             long-array
123             anonymous-rejected
124             illegal-aux-item
125             aux-item-permission
126             unknown-async
127             internal-error
128             feature-disabled
129             message-not-sent
130             invalid-membership-type);
131              
132              
133             ## Methods
134              
135             =item is_error($code, $err_no, $err_status)
136              
137             Looks at a response from the server and decides if it is an error
138             message and if that is the case sets some variables in the object and
139             returns true.
140              
141             Calls C if the response does not look as a server response at
142             all.
143              
144             This sub is intended for internal use.
145              
146             =cut
147              
148             sub is_error {
149 13     13 1 37 my $self = shift;
150 13         52 my ($code, $err_no, $err_status) = @_;
151              
152 13 50       113 if ($code =~ /^=/) {
    0          
    0          
153 13         64 $self->{err_no} = 0;
154 13         40 $self->{err_status} = 0;
155 13         47 $self->{err_string} = "";
156 13         87 return 0; # Not an error
157             } elsif ($code =~ /^%%/) {
158 0         0 $self->{err_no} = 4711;
159 0         0 $self->{err_status} = $err_status;
160 0         0 $self->{err_string} = "Protocol error!";
161 0         0 return 1; # Is an error
162             } elsif ($code =~ /^%/) {
163 0         0 $self->{err_no} = $err_no;
164 0         0 $self->{err_status} = $err_status;
165 0         0 $self->{err_string} = $error[$err_no];
166 0         0 return 1; # Is an error
167             } else {
168 0         0 croak "An unknown error? ($code)\n";
169             }
170             }
171              
172 0     0 0 0 sub err_no {my $s = shift; return $s->{err_no}}
  0         0  
173 0     0 0 0 sub err_status {my $s = shift; return $s->{err_status}}
  0         0  
174 0     0 0 0 sub err_string {my $s = shift; return $s->{err_string}}
  0         0  
175              
176             =item new([options])
177              
178             Creates a new Net::Lyskom object and connect to a LysKOM server. By
179             default it connects to the server at Lysator (I,
180             port 4894). To connect to another server, use named arguments.
181              
182             $a = Net::Lyskom->new(Host => "kom.csd.uu.se", Port => 4894);
183              
184             If the connection succeded, an object is returned, if not C is
185             returned.
186              
187             =cut
188              
189             sub new {
190 1     1 1 16 my $proto = shift;
191 1   33     10 my $class = ref($proto) || $proto;
192 1         2 my $self = {};
193 1         4 my %arg = @_;
194              
195 1   50     6 my $host = $arg{Host} || "kom.lysator.liu.se";
196 1   50     6 my $port = $arg{Port} || 4894;
197              
198 1   33     2315 my $name =
199             $arg{Name} ||
200             $ENV{USER} ||
201             $ENV{LOGNAME} ||
202             ((getpwuid($<))[0]);
203              
204 1         11 $self->{refno} = 1;
205              
206 1 50       21 $self->{socket} = IO::Socket::INET->new(
207             PeerAddr => $host,
208             PeerPort => $port,
209             )
210             or croak "Can't connect to remote server: $!\n";
211              
212 1         87282 $self->{socket}->print("A".holl($name)."\n");
213              
214 1         188 my $tmp = $self->{socket}->getline;
215 1   33     49577 while (!$tmp || $tmp !~ /LysKOM/) {
216 0         0 $tmp = $self->{socket}->getline;
217             }
218              
219 1         9 bless $self, $class;
220 1         10 return $self;
221             }
222              
223             =item getres()
224              
225             Get responses and asynchronous messages from the server. The asynchronous
226             messages is passed to C. This method is intended for
227             internal use, and shall normally not be used anywhere else then in
228             this module.
229              
230             =cut
231              
232             sub getres {
233 13     13 1 35 my $self = shift;
234 13         24 my @res;
235              
236 13         54 @res = $self->getres_sub;
237 13         127 while ($res[0] =~ m/^:/) {
238 0         0 $self->handle_asynch(@res);
239 0         0 @res = $self->getres_sub;
240             }
241 13         702 return @res;
242             }
243              
244             =item getres_sub()
245              
246             Helper function to C. Be careful and I what you are
247             up to before using it.
248              
249             =cut
250              
251             sub getres_sub {
252 13     13 1 28 my $self = shift;
253 13         26 my ($f, $r);
254 0         0 my @res;
255              
256 13         762 $r = $self->{socket}->getline;
257 13         582293 while ($r) {
258 1771 100       32963 if ($r =~ m|^(\d+)H(.*)$|) { # Start of a hollerith string
259 267         511 my $tot_len = $1;
260 267         291 my $res;
261 267         3764 $r = $2."\n";
262            
263 267         1345 $res = substr $r, 0, $tot_len,"";
264 267         632 while (length($res) < $tot_len) {
265 29         809 $r = $self->{socket}->getline;
266 29         751 debug($r);
267 29         82 $res .= substr $r, 0, ($tot_len-length($res)),"";
268             }
269 267         452 push @res, $res;
270 267 50       485 if ($r eq "") {
271 0         0 $r = $self->{socket}->getline;
272             }
273 267         1453 $r =~ s/^ //;
274             } else {
275 1504         24242 ($f, $r) = split " ", $r, 2;
276 1504         5621 push @res,$f;
277             }
278             }
279 13         777 return @res;
280             }
281              
282             sub send {
283 13     13 0 28 my $s = shift;
284              
285 13         117 $s->{socket}->print(@_);
286             }
287              
288             =item handle_asynch()
289              
290             Is automaticly called when a asynchronous message is returned from
291             the server. Currently this routine does nothing.
292              
293             =cut
294              
295             sub handle_asynch {
296 0     0 1 0 my $self = shift;
297 0         0 my @call = @_;
298              
299             #debug "Asynch: @call";
300             }
301              
302             ## Server calls
303              
304             =item logout
305              
306             Log out from LysKOM, this call does not disconnect the session, which
307             means you can login again without the need of calling another new.
308              
309             $a->logout();
310              
311             =cut
312              
313             sub logout {
314 1     1 1 4 my $self = shift;
315              
316 1         10 return $self->gen_call_boolean(1);
317             }
318              
319             =item change_conference ($conference)
320              
321             Changes current conference of the session.
322              
323             $a->change_conference(4711);
324              
325             =cut
326              
327             sub change_conference {
328 1     1 1 3 my $self = shift;
329 1         2 my $conference = shift;
330              
331 1         7 return $self->gen_call_boolean(2,$conference);
332             }
333              
334             =item change_name ($conference, $new_name)
335              
336             Change name of the person or conference numbered $conference to $new_name.
337              
338             $a->change_name(46, 'Sweden (the strange land)');
339              
340             =cut
341              
342             sub change_name {
343 0     0 1 0 my $self = shift;
344 0         0 my $conference = shift;
345 0         0 my $new_name = shift;
346              
347 0         0 return $self->gen_call_boolean(3, $conference, holl($new_name));
348             }
349              
350             =item change_what_i_am_doing ($what_am_i_doing)
351              
352             Tells the server what the logged-in user is doing. You are encouraged to use
353             this call creatively.
354              
355             $a->change_what_i_am_doing('Eating smorgasbord');
356              
357             =cut
358              
359             sub change_what_i_am_doing {
360 1     1 1 4 my $self = shift;
361 1         3 my $what_am_i_doing = shift;
362              
363 1         9 return $self->gen_call_boolean(4, holl($what_am_i_doing));
364             }
365              
366             =item set_priv_bits($person, admin => 1, wheel => 1, statistic => 1, create_pers => 1, create_conf => 1, change_name => 1)
367              
368             Set the privbits on person $person. User can specify one or more
369             privileges by name. Privs not specified default to false.
370              
371             =cut
372              
373             sub set_priv_bits {
374 0     0 1 0 my $self = shift;
375 0         0 my $person = shift;
376 0         0 my %priv = (
377             wheel => 0,
378             admin => 0,
379             statistic => 0,
380             create_pers => 0,
381             create_conf => 0,
382             change_name => 0
383             );
384 0         0 my %arg = @_;
385              
386 0         0 foreach (keys %arg) {
387 0         0 $priv{$_} = $arg{$_}
388             }
389              
390 0 0       0 my $pstring = join "", map {$_?"1":"0"}
  0         0  
391             (
392             $priv{wheel},
393             $priv{admin},
394             $priv{statistic},
395             $priv{create_pers},
396             $priv{create_conf},
397             $priv{change_name},
398             0, 0, 0, 0, 0, 0, 0, 0, 0, 0
399             );
400              
401 0         0 return $self->gen_call_boolean(7, $person, $pstring);
402             }
403              
404             =item set_passwd(person => $person, old_pwd => $old, new_pwd => $new)
405              
406             Changes the password of $person to $new_pwd.
407              
408             $old is the password of the currently logged in person. All three
409             arguments are required.
410              
411             =cut
412              
413             sub set_passwd {
414 0     0 1 0 my $self = shift;
415 0         0 my %arg = @_;
416              
417 0         0 return $self->gen_call_boolean(8,
418             $arg{person},
419             holl($arg{old_pwd}),
420             holl($arg{new_pwd})
421             );
422             }
423              
424             =item delete_conf($conf)
425              
426             Deletes the conference with number $conf. If $conf is a mailbox,
427             the corresponding user is also deleted.
428              
429             $a->delete_conf(42);
430              
431             =cut
432              
433             sub delete_conf {
434 0     0 1 0 my $self = shift;
435 0         0 my $conf = shift;
436              
437 0         0 return $self->gen_call_boolean(11, $conf);
438             }
439              
440             =item sub_member($conf_no, $pers_no)
441              
442             Removes the person $pers_no from the membership list of
443             conference $conf_no.
444              
445             $a->sub_member(42,4711);
446              
447             =cut
448              
449             sub sub_member {
450 0     0 1 0 my $self = shift;
451 0         0 my $conf_no = shift;
452 0         0 my $pers_no = shift;
453              
454 0         0 return $self->gen_call_boolean(15, $conf_no, $pers_no);
455             }
456              
457             =item set_presentation($conf_no, $text_no)
458              
459             Set the text $text_no as presentation for $conf_no.
460             To remove a presentation, use $text_no = 0
461              
462             $a->set_presentation(42,4711);
463              
464             =cut
465              
466             sub set_presentation {
467 0     0 1 0 my $self = shift;
468 0         0 my $conf_no = shift;
469 0         0 my $text_no = shift;
470              
471 0         0 return $self->gen_call_boolean(16, $conf_no, $text_no);
472             }
473              
474             =item set_etc_motd($conf_no, $text_no)
475              
476             Sets the messages of the day on the conference or person $conf_no to
477             $text_no and removes the old message.
478              
479             $a->set_etc_motd(6,1);
480              
481             =cut
482              
483             sub set_etc_motd {
484 0     0 1 0 my $self = shift;
485 0         0 my $conf_no = shift;
486 0         0 my $text_no = shift;
487              
488 0         0 return $self->gen_call_boolean(17, $conf_no, $text_no);
489             }
490              
491              
492             =item set_supervisor($conf_no, $admin)
493              
494             Set person/conference $admin as supervisor for the
495             conference $conf_no
496              
497             =cut
498              
499             sub set_supervisor {
500 0     0 1 0 my $self = shift;
501 0         0 my $conf_no = shift;
502 0         0 my $admin = shift;
503              
504 0         0 return $self->gen_call_boolean(18, $conf_no, $admin);
505             }
506              
507             =item set_permitted_submitters($conf_no, $perm_sub)
508              
509             Set $perm_sub as permitted subscribers for $conf_no. If $perm_sub = 0,
510             all users are welcome to write in the conference.
511              
512             =cut
513              
514             sub set_permitted_submitters {
515 0     0 1 0 my $self = shift;
516 0         0 my $conf_no = shift;
517 0         0 my $perm_sub = shift;
518              
519 0         0 return $self->gen_call_boolean(19, $conf_no, $perm_sub);
520             }
521              
522             =item set_super_conf($conf_no, $super_conf)
523              
524             Sets the conference $super_conf as super conference for $conf_no
525              
526             =cut
527              
528             sub set_super_conf {
529 0     0 1 0 my $self = shift;
530 0         0 my $conf_no = shift;
531 0         0 my $super_conf = shift;
532              
533 0         0 return $self->gen_call_boolean(20, $conf_no, $super_conf);
534             }
535              
536             =item set_garb_nice($conf_no, $nice)
537              
538             Sets the garb time for the conference $conf_no to $nice days.
539              
540             $a->set_garb_nice(42,7);
541              
542             =cut
543              
544             sub set_garb_nice {
545 0     0 1 0 my $self = shift;
546 0         0 my $conf_no = shift;
547 0         0 my $nice = shift;
548              
549 0         0 return $self->gen_call_boolean(22, $conf_no, $nice);
550             }
551              
552             =item get_text(text => $text, start_char => $start, end_char => $end)
553              
554             Get a text from the server, the first argument, C, is the global
555             text number for the text to get. The retrival stars at position
556             C (the first character in the text is numbered 0) and ends
557             at position C.
558              
559             Default is 0 for C and 2147483647 for C. This
560             means that a complete message is fetched, unless otherwise stated.
561              
562             Also note that you can get an entire text, pre-split into subject and
563             body, via the object returned from the C method.
564              
565             To get the first 100 chars from text 4711:
566              
567             my $text = $a->get_text(text => 4711, start_char => 0, end_char => 100);
568              
569             =cut
570              
571             sub get_text {
572 1     1 1 2 my $self = shift;
573 1         5 my %arg = @_;
574 1         2 my @res;
575              
576 1 50       4 unless ($arg{text}) {
577 0         0 croak "get_text() called with no text number argument";
578             }
579 1 50       5 $arg{start_char} = 0 unless $arg{start_char};
580 1 50       5 $arg{end_char} = 2147483647 unless $arg{end_char};
581              
582 1         11 return $self->gen_call_scalar(25, $arg{text}, $arg{start_char}, $arg{end_char});
583             }
584              
585             =item delete_text($text)
586              
587             Deletes the text with the global text number $text from the database.
588              
589             =cut
590              
591             sub delete_text {
592 0     0 1 0 my $self = shift;
593 0         0 my $text = shift;
594              
595 0         0 return $self->gen_call_boolean(29, $text);
596             }
597              
598             =item add_recipient(text_no => $text, conf_no => $conf, type => $type)
599              
600             Add a recipient to a text. $type can be one of "recpt", "cc" or "bcc".
601             If not given (or if set to something other than one of those three
602             strings) it defaults to "recpt". C and C are
603             required.
604              
605             =cut
606              
607             sub add_recipient {
608 0     0 1 0 my $self = shift;
609 0         0 my %arg = @_;
610              
611 0 0       0 if ($arg{type} eq "bcc") {
    0          
612 0         0 $arg{type} = 15
613             } elsif ($arg{type} eq "cc") {
614 0         0 $arg{type} = 1
615             } else {
616 0         0 $arg{type} = 0
617             }
618 0         0 return $self->gen_call_boolean(30,$arg{text_no},$arg{conf_no},$arg{type});
619             }
620              
621             =item sub_recipient($text_no, $conf_no)
622              
623             Remove a recipient from a text.
624              
625             =cut
626              
627             sub sub_recipient {
628 0     0 1 0 my $self = shift;
629 0         0 my $textno = shift;
630 0         0 my $confno = shift;
631              
632 0         0 return $self->gen_call_boolean(31, $textno, $confno);
633             }
634              
635             =item add_comment($text_no, $comment_to)
636              
637             Add a comment link between the text comment-to and the text text-no
638             (text-no becomes a comment to the text comment-to). This call is used
639             to add comment links after a text has been created.
640              
641             =cut
642              
643             sub add_comment {
644 0     0 1 0 my $self = shift;
645 0         0 my $textno = shift;
646 0         0 my $commentto = shift;
647              
648 0         0 return $self->gen_call_boolean(32, $textno, $commentto);
649             }
650              
651             =item get_time
652              
653             Ask the server for the current time. Returns a L object.
654              
655             =cut
656              
657             sub get_time {
658 1     1 1 1004 my $self = shift;
659 1         3 my @res;
660              
661 1         13 @res = $self->server_call(35);
662 1 50       9 if ($self->is_error(@res)) {
663 0         0 return undef;
664             } else {
665 1         29 shift @res; # Remove return code
666 1         19 return Net::Lyskom::Time->new_from_stream(\@res);
667             }
668             }
669              
670             =item set_unread($conf_no, $no_of_unread)
671              
672             Only read the $no_of_unread texts in the conference $conf_no.
673              
674             =cut
675              
676             sub set_unread {
677 0     0 1 0 my $self = shift;
678 0         0 my $conf_no = shift;
679 0         0 my $no_of_unread = shift;
680              
681 0         0 return $self->gen_call_boolean(40, $conf_no, $no_of_unread);
682             }
683              
684             =item set_motd_of_lyskom($text_no)
685              
686             Sets the login message of LysKOM, can only be executed by a privileged person,
687             with the proper privileges enabled.
688              
689             =cut
690              
691             sub set_motd_of_lyskom {
692 0     0 1 0 my $self = shift;
693 0         0 my $text_no = shift;
694              
695 0         0 return $self->gen_call_boolean(41, $text_no);
696             }
697              
698             =item enable($level)
699              
700             Sets the security level for the current session to $level.
701              
702             =cut
703              
704             sub enable {
705 0     0 1 0 my $self = shift;
706 0         0 my $level = shift;
707              
708 0         0 return $self->gen_call_boolean(42, $level);
709             }
710              
711             =item sync_kom
712              
713             This call instructs the LysKOM server to make sure the permanent copy of its
714             databas is current. This call is privileged in most implementations.
715              
716             $a->sync_kom();
717              
718             =cut
719              
720             sub sync_kom {
721 0     0 1 0 my $self = shift;
722              
723 0         0 return $self->gen_call_boolean(43);
724             }
725              
726             =item shutdown_kom($exit_val)
727              
728             Instructs the server to save all data and shut down. The variable $exit_val is
729             currently not used.
730              
731             =cut
732              
733             sub shutdown_kom {
734 0     0 1 0 my $self = shift;
735 0         0 my $exit_val = shift;
736              
737 0         0 return $self->gen_call_boolean(44, $exit_val);
738             }
739              
740             =item get_person_stat($persno)
741              
742             Get status for a person from the server. Returns a L
743             object.
744              
745             =cut
746              
747             sub get_person_stat {
748 1     1 1 6 my $self = shift;
749 1         7 my $persno = shift;
750 1         5 my @res;
751              
752 1         8 @res = $self->server_call(49, $persno);
753 1 50       11 if ($self->is_error(@res)) {
754 0         0 return 0;
755             } else {
756 1         2 shift @res; # Remove return code
757 1         20 return Net::Lyskom::Person->new_from_stream(\@res);
758             }
759             }
760              
761             =item get_unread_confs($pers_no)
762              
763             Get a list of conference numbers in which the person $pers_no
764             may have unread texts.
765              
766             my @unread_confs = $a->get_unread_confs(7);
767              
768             =cut
769              
770             sub get_unread_confs {
771 0     0 1 0 my $self = shift;
772 0         0 my $pers_no = shift;
773 0         0 my @res;
774              
775 0         0 @res = $self->server_call(52, $pers_no);
776 0 0       0 if ($self->is_error(@res)) {
777 0         0 return ();
778             } else {
779 0         0 shift @res; # Remove return code
780 0     0   0 return parse_array_stream(sub{shift @{$_[0]}},\@res);
  0         0  
  0         0  
781             }
782              
783             }
784              
785             =item send_message($recipient, $message)
786              
787             Sends the message $message to all members of $recipient that is
788             currently logged in. If $recipient is 0, the message is sent to all
789             sessions that are logged in.
790              
791             =cut
792              
793             sub send_message {
794 0     0 1 0 my $self = shift;
795 0         0 my $recipient = shift;
796 0         0 my $message = shift;
797              
798 0         0 return $self->gen_call_boolean(53, $recipient, holl($message));
799             }
800              
801             =item who_am_i
802              
803             Get the session number of the current session.
804              
805             my $session_number = $a->who_am_i();
806              
807             =cut
808              
809             sub who_am_i {
810 1     1 1 2 my $self = shift;
811              
812 1         6 return $self->gen_call_scalar(56);
813             }
814              
815             =item get_last_text($time)
816              
817             $time should be given a as a unix time_t (that is, as the number of
818             seconds since 00:00:00 01 Jan 1970 UCT).
819              
820             =cut
821              
822             sub get_last_text {
823 0     0 1 0 my $self = shift;
824 0         0 my $time = shift;
825              
826 0         0 my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
827             localtime($time);
828 0 0       0 return $self->gen_call_scalar(58,$sec,$min,$hour,$mday,$mon,$year,$wday,
829             $yday,($isdst?1:0));
830             }
831              
832             =item find_next_text_no($text_no)
833              
834             Returns the global number of the readable text that follows the text
835             C<$text_no>.
836              
837             =cut
838              
839             sub find_next_text_no {
840 0     0 1 0 my $self = shift;
841 0         0 my $start = shift;
842              
843 0         0 return $self->gen_call_scalar(60, $start);
844             }
845              
846             =item find_previous_text_no($text_no)
847              
848             Returns the global number of the readable text that precedes the text
849             C<$text_no>.
850              
851             =cut
852              
853             sub find_previous_text_no {
854 0     0 1 0 my $self = shift;
855 0         0 my $start = shift;
856              
857 0         0 return $self->gen_call_scalar(61, $start);
858             }
859              
860             =item login(pers_no => $pers, password => $pwd, invisible => $invis)
861              
862             Log in to LysKOM. $persno is the number of the person which is to be
863             logged in. $pwd is the password of that person. If $invis is true, a
864             secret login is done (the session is not visible in who-is-on-lists et al.)
865              
866             =cut
867              
868             sub login {
869 1     1 1 5 my $self = shift;
870 1         10 my %arg = @_;
871              
872 1 50       8 return $self->gen_call_boolean(62,
873             $arg{pers_no},
874             holl($arg{password}),
875             ($arg{invisible})?1:0);
876             }
877              
878             =item set_client_version($client_name, $client_version)
879              
880             Tells the server that this is the software $client_name and the
881             version $client_version.
882              
883             $a->set_client_version('My-cool-software','0.001 beta');
884              
885             =cut
886              
887             sub set_client_version {
888 0     0 1 0 my $self = shift;
889 0         0 my $client_name = shift;
890 0         0 my $client_version = shift;
891              
892 0         0 return $self->gen_call_boolean(69, holl($client_name), holl($client_version));
893             }
894              
895             =item get_client_name($session)
896              
897             Ask the server for the name of the client software logged in with
898             session number $session.
899              
900             =cut
901              
902             sub get_client_name {
903 0     0 1 0 my $self = shift;
904 0         0 my $session = shift;
905              
906 0         0 return $self->gen_call_scalar(70, $session);
907             }
908              
909             =item get_client_version($session)
910              
911             Ask the server for the version of the client software logged in with
912             session number $session.
913              
914             =cut
915              
916             sub get_client_version {
917 0     0 1 0 my $self = shift;
918 0         0 my $session = shift;
919              
920 0         0 return $self->gen_call_scalar(71, $session);
921             }
922              
923             =item get_version_info
924              
925             Ask the server for the version info of the server software itself.
926             Returns a three-element array with the protocol version, server
927             software name and server software version.
928              
929             =cut
930              
931             sub get_version_info {
932 0     0 1 0 my $self = shift;
933 0         0 my @res;
934              
935 0         0 @res = $self->server_call(75);
936 0 0       0 if ($self->is_error(@res)) {
937 0         0 return ();
938             } else {
939 0         0 shift @res; # Remove return code
940 0         0 return @res[0..2];
941             }
942             }
943              
944             =item lookup_z_name(name => $name, want_pers => $wp, want_conf => $wc)
945              
946             Lookup the name $name in the server, returns a list of all matching
947             conferences and/or persons, in the form of L
948             objects. The server database is searched with standard kom name
949             expansion.
950              
951             If $want_pers is true, the server includes persons in the answer, if
952             $want_conf is true, conferences is included.
953              
954             =cut
955              
956             sub lookup_z_name {
957 1     1 1 4 my $self = shift;
958 1         2 my @res;
959 1         5 my %arg = @_;
960              
961 1 50       7 @res = $self->server_call(76,
    50          
962             holl($arg{name}),
963             ($arg{want_pers}?1:0),
964             ($arg{want_conf}?1:0));
965 1 50       12 if ($self->is_error(@res)) {
966 0         0 return 0;
967             } else {
968 1         2 shift @res; # Remove return code
969 1     1   17 return parse_array_stream(sub{Net::Lyskom::ConfZInfo->new_from_stream(@_)},\@res)
  1         16  
970             }
971             }
972              
973             =item re_z_lookup(name => $name, want_pers => $wp, want_conf => $wc)
974              
975             Regexp lookup of the name $name in the server, returns a list of all
976             matching conferences and/or persons, in the form of
977             L objects.
978              
979             If $want_pers is true, the server includes persons in the answer, if
980             $want_conf is true, conferences is included.
981              
982             =cut
983              
984             sub re_z_lookup {
985 0     0 1 0 my $self = shift;
986 0         0 my @res;
987 0         0 my %arg = @_;
988              
989 0 0       0 @res = $self->server_call(74,
    0          
990             holl($arg{name}),
991             ($arg{want_pers}?1:0),
992             ($arg{want_conf}?1:0));
993 0 0       0 if ($self->is_error(@res)) {
994 0         0 return 0;
995             } else {
996 0         0 shift @res; # Remove return code
997 0     0   0 return parse_array_stream(sub{Net::Lyskom::ConfZInfo->new_from_stream(@_)},\@res)
  0         0  
998             }
999             }
1000              
1001             =item user_active
1002              
1003             Tells the server that the user is active.
1004              
1005             =cut
1006              
1007             sub user_active {
1008 0     0 1 0 my $self = shift;
1009              
1010 0         0 return $self->gen_call_boolean(82);
1011             }
1012              
1013             =item who_is_on_dynamic(want_visible => $wv, want_invisible => $wi, active_last => $al)
1014              
1015             Returns a list of L objects. If
1016             C is true, the visible users are included in the answer.
1017             If C is true, invisible users are included.
1018              
1019             Only the users active the last C seconds are included in
1020             the answer. If C is zero, all users (who match the
1021             visibility limits) are returned.
1022              
1023             If not given, C defaults to true, C
1024             defaults to false and C defaults to 0.
1025              
1026             =cut
1027              
1028             sub who_is_on_dynamic {
1029 1     1 1 5 my $self = shift;
1030 1         12 my %arg = @_;
1031 1         4 my @res;
1032              
1033 1 50       6 $arg{want_visible} = 1 unless $arg{want_visible};
1034 1 50       6 $arg{want_invisible} = 0 unless $arg{want_invisible};
1035 1 50       5 $arg{active_last} = 0 unless $arg{active_last};
1036              
1037 1 50       24 @res = $self->server_call(83,
    50          
1038             ($arg{want_visible}?1:0),
1039             ($arg{want_invisible}?1:0),
1040             $arg{active_last});
1041 1 50       115 if ($self->is_error(@res)) {
1042 0         0 return 0;
1043             } else {
1044 1         3 shift @res; # Remove return code
1045 1     261   20 return parse_array_stream(sub{Net::Lyskom::DynamicSession->new_from_stream(@_)},\@res)
  261         668  
1046             }
1047             }
1048              
1049             =item get_static_session_info($session_no)
1050              
1051             Returns a C object holding details on the
1052             specified session.
1053              
1054             =cut
1055              
1056             sub get_static_session_info {
1057 0     0 1 0 my $self = shift;
1058 0         0 my $session = shift;
1059 0         0 my @res;
1060              
1061 0         0 @res = $self->server_call(84, $session);
1062 0 0       0 if ($self->is_error(@res)) {
1063 0         0 return undef;
1064             } else {
1065 0         0 shift @res;
1066 0         0 return Net::Lyskom::StaticSession->new_from_stream(\@res);
1067             }
1068             }
1069              
1070              
1071             =item create_text(subject => "This is the subject", body => "This is the text body.", recpt => [6], cc_recpt => [437], bcc_recpt => [19, 23], comm_to => [4711], footn_to => [11147], aux => [@aux_obj_list])
1072              
1073             Creates texts. Takes arguments as indicated in the synopsis just above
1074             (that is, as a hash with zero or more of the given keys and strings or
1075             arrayrefs as values, as appropriate). Any of the arguments can be left
1076             out, but a text without at least one recipient is not very useful (nor
1077             is one with neither subject nor body). The C argument should be a
1078             reference to a list of L objects.
1079              
1080             If the C list is not given, or given but not containing a
1081             content-type item, an item with content type
1082             C will be added. In this case, the
1083             subject and body will also be converted from Perl's internal encoding
1084             to UTF-8 before being sent out over the network.
1085              
1086             Example:
1087              
1088             $k->create_text(
1089             subject => "Test",
1090             body => "Body",
1091             recpt => [437],
1092             aux => [
1093             Net::Lyskom::AuxItem->new(
1094             tag => content_type,
1095             data => "text/plain"
1096             )
1097             ]);
1098              
1099              
1100             =cut
1101              
1102             sub create_text {
1103 0     0 1 0 my $self = shift;
1104 0         0 my %arg = @_;
1105 0         0 my @misc;
1106 0         0 my $misc_count = 0;
1107 0         0 my @aux;
1108 0         0 my $aux_count = 0;
1109 0         0 my @call;
1110              
1111 0 0 0     0 if (
1112 0         0 !$arg{aux}
1113 0         0 or scalar(grep {$_->tag == 1} @{$arg{aux}})==0
1114             ) {
1115             # No Aux-items, or at least no Content-Type
1116 0         0 push @{$arg{aux}}, Net::Lyskom::AuxItem->new(
  0         0  
1117             tag => 'content_type',
1118             data => 'text/x-kom-basic;charset=utf-8'
1119             );
1120 0         0 $arg{subject} = encode_utf8($arg{subject});
1121 0         0 $arg{body} = encode_utf8($arg{body});
1122             }
1123              
1124 0         0 push @call, holl($arg{subject}."\n".$arg{body});
1125 0 0       0 if ($arg{recpt}) {
1126 0         0 foreach (@{$arg{recpt}}) {
  0         0  
1127 0         0 push @misc, 0, $_;
1128 0         0 $misc_count++;
1129             }
1130             }
1131 0 0       0 if ($arg{cc_recpt}) {
1132 0         0 foreach (@{$arg{cc_recpt}}) {
  0         0  
1133 0         0 push @misc, 1, $_;
1134 0         0 $misc_count++;
1135             }
1136             }
1137 0 0       0 if ($arg{bcc_recpt}) {
1138 0         0 foreach (@{$arg{bcc_recpt}}) {
  0         0  
1139 0         0 push @misc, 15, $_;
1140 0         0 $misc_count++;
1141             }
1142             }
1143 0 0       0 if ($arg{comm_to}) {
1144 0         0 foreach (@{$arg{comm_to}}) {
  0         0  
1145 0         0 push @misc, 2, $_;
1146 0         0 $misc_count++;
1147             }
1148             }
1149 0 0       0 if ($arg{footn_to}) {
1150 0         0 foreach (@{$arg{footn_to}}) {
  0         0  
1151 0         0 push @misc, 4, $_;
1152 0         0 $misc_count++;
1153             }
1154             }
1155 0         0 push @call, $misc_count, '{', @misc, '}';
1156              
1157 0 0       0 if ($arg{aux}) {
1158 0         0 foreach (@{$arg{aux}}) {
  0         0  
1159 0         0 push @aux, $_->to_server;
1160 0         0 $aux_count++;
1161             }
1162             }
1163 0         0 push @call, $aux_count, '{', @aux, '}';
1164              
1165 0         0 return $self->gen_call_scalar(86, @call);
1166             }
1167              
1168             =item get_text_stat($textno)
1169              
1170             Fetch the status for a text from the server. Returns a
1171             L object.
1172              
1173             =cut
1174              
1175             sub get_text_stat {
1176 1     1 1 683 my $self = shift;
1177 1         3 my $textno = shift;
1178 1         3 my @res;
1179              
1180 1         6 @res = $self->server_call(90, $textno);
1181 1 50       12 if ($self->is_error(@res)) {
1182 0         0 return 0;
1183             } else {
1184 1         3 shift @res; # Remove return code
1185 1         21 return Net::Lyskom::TextStat->new_from_stream($self, $textno, \@res);
1186             }
1187             }
1188              
1189             =item get_conf_stat(@conf_no)
1190              
1191             Get status for one or more conferences from the server. Returns a
1192             L object in scalar context and a list of such
1193             objects in list context.
1194              
1195             =cut
1196              
1197             sub get_conf_stat {
1198 1     1 1 3 my $self = shift;
1199 1         4 my @confno = @_;
1200 1         2 my @res;
1201             my @tmp;
1202              
1203 1         4 @tmp = $self->server_call([map {[91,$_]} @confno]);
  1         13  
1204 1         5 foreach (@tmp) {
1205 1 50       2 if ($self->is_error(@{$_})) {
  1         10  
1206 0         0 push @res,undef;
1207             } else {
1208 1         4 shift @{$_}; # Remove return code
  1         4  
1209 1         18 push @res, Net::Lyskom::Conference->new_from_stream($_);
1210             }
1211             }
1212              
1213 1 50       4 if (wantarray) {
1214 0         0 return @res;
1215             } else {
1216 1         9 return $res[0];
1217             }
1218             }
1219              
1220             =item modify_text_info( text => $text, delete => $delete_array_ref, add => $add_array_ref)
1221              
1222             Add and/or delete aux items to/from a text. C should be a
1223             reference to an array of aux_info order numbers to remove from the
1224             text. C should be a reference to an array of
1225             C objects to add to the text.
1226              
1227             =cut
1228              
1229             sub modify_text_info {
1230 0     0 1 0 my $self = shift;
1231 0         0 my %arg = @_;
1232 0         0 my @aux;
1233 0         0 my $aux_count = 0;
1234 0         0 my @del;
1235 0         0 my $del_count = 0;
1236 0         0 my @call;
1237              
1238 0         0 push @call, 92;
1239 0         0 push @call, $arg{text};
1240              
1241 0 0       0 if ($arg{delete}) {
1242 0         0 foreach (@{$arg{delete}}) {
  0         0  
1243 0         0 push @del, $_;
1244 0         0 $del_count++;
1245             }
1246             }
1247 0         0 push @call, $del_count, '{', @del, '}';
1248              
1249 0 0       0 if ($arg{add}) {
1250 0         0 foreach (@{$arg{add}}) {
  0         0  
1251 0         0 push @aux, $_->to_server;
1252 0         0 $aux_count++;
1253             }
1254             }
1255 0         0 push @call, $aux_count, '{', @aux, '}';
1256              
1257 0         0 return $self->gen_call_boolean(@call);
1258             }
1259              
1260             =item butt_ugly_fast_reply($text, $data)
1261              
1262             Adds a fast-reply auxitem with the contents $data to the text $text.
1263             Now implemented in terms of C, name retained for
1264             backwards compatibility.
1265              
1266             =cut
1267              
1268             sub butt_ugly_fast_reply { # Less ugly re-implementation
1269 0     0 1 0 my $self = shift;
1270 0         0 my ($text, $data) = @_;
1271              
1272 0         0 $self->modify_text_info(
1273             text => $text,
1274             add => [
1275             Net::Lyskom::AuxItem->new(
1276             tag => "fast_reply",
1277             data => $data
1278             )
1279             ]
1280             );
1281             }
1282              
1283             =item query_predefined_aux_items
1284              
1285             Ask the server which predefined aux items that exists in the server.
1286              
1287             =cut
1288              
1289             sub query_predefined_aux_items {
1290 0     0 1 0 my $self = shift;
1291 0         0 my @res;
1292              
1293 0         0 @res = $self->server_call(96);
1294 0 0       0 if ($self->is_error(@res)) {
1295 0         0 return ();
1296             } else {
1297 0         0 shift @res;
1298 0     0   0 return parse_array_stream(sub{shift @{$_[0]}},\@res);
  0         0  
  0         0  
1299             }
1300             }
1301              
1302             =item get_membership(person => $p, first => $f, no_of_confs => $no, want_read_texts => $w)
1303              
1304             Get a membership list for C, in the form of a list of
1305             L objects. Start at position C in the
1306             membership list and get C conferences. If
1307             C is true the server will also send information about
1308             read texts in the conference.
1309              
1310             =cut
1311              
1312             sub get_membership {
1313 0     0 1 0 my $self = shift;
1314 0         0 my %arg = @_;
1315 0         0 my @res;
1316              
1317 0 0       0 $arg{first} = 0 unless $arg{first};
1318 0 0       0 $arg{no_of_confs} = 10 unless $arg{no_of_confs};
1319 0 0       0 $arg{want_read_texts} = 1 unless $arg{want_read_texts};
1320              
1321 0 0       0 @res = $self->server_call(99,
1322             $arg{person},
1323             $arg{first},
1324             $arg{no_of_confs},
1325             ($arg{want_read_texts})?1:0);
1326 0 0       0 if ($self->is_error(@res)) {
1327 0         0 return ();
1328             } else {
1329 0         0 shift @res; # Remove return code
1330 0     0   0 return parse_array_stream(sub{Net::Lyskom::Membership->new_from_stream(@_)},\@res);
  0         0  
1331             }
1332             }
1333              
1334             =item local_to_global(conf => $conf, first => $first, number => $no)
1335              
1336             Given a local text number and an integer smaller than 256, returns a
1337             L object detailing the mapping between the
1338             local and global text numbers of up to that many texts. All arguments
1339             are required.
1340              
1341             =cut
1342              
1343             sub local_to_global {
1344 1     1 1 2 my $self = shift;
1345 1         5 my %arg = @_;
1346 1         2 my @res;
1347              
1348 1         8 @res = $self->server_call(103, $arg{conf}, $arg{first}, $arg{number});
1349 1 50       8 if ($self->is_error(@res)) {
1350 0         0 return ();
1351             } else {
1352 1         3 shift @res; # Remove return code
1353 1         16 return Net::Lyskom::TextMapping->new_from_stream(\@res);
1354             }
1355             }
1356              
1357             =item map_created_texts(pers_no => $pers, first => $first, number => $no)
1358              
1359             Given a local text number and an integer smaller than 256, returns a
1360             L object detailing the mapping between texts
1361             written by C and global text numbers of up to that many
1362             texts. All arguments are required.
1363              
1364             =cut
1365              
1366             sub map_created_texts {
1367 0     0 1   my $self = shift;
1368 0           my %arg = @_;
1369 0           my @res;
1370              
1371 0           @res = $self->server_call(104, $arg{pers_no}, $arg{first}, $arg{number});
1372 0 0         if ($self->is_error(@res)) {
1373 0           return ();
1374             } else {
1375 0           shift @res; # Remove return code
1376 0           return Net::Lyskom::TextMapping->new_from_stream(\@res);
1377             }
1378             }
1379              
1380             =item set_membership_type(pers => $p, conf => $c, invitation => $i, passive => $pa, secret => $s)
1381              
1382             Set the membership flags for user C in conference C.
1383              
1384             =cut
1385              
1386             sub set_membership_type {
1387 0     0 1   my $self = shift;
1388 0           my %arg = @_;
1389 0 0         my $str = sprintf "%s%s%s00000",
    0          
    0          
1390             ($arg{invitation}?"1":"0"),
1391             ($arg{passive}?"1":"0"),
1392             ($arg{secret}?"1":"0");
1393              
1394 0           return $self->gen_call_boolean(102, $arg{pers}, $arg{conf}, $str);
1395             }
1396              
1397             =item get_members(conf => $conf_no, first => $first_index, $count => $no_of_members)
1398              
1399             =cut
1400              
1401             sub get_members {
1402 0     0 1   my $self = shift;
1403 0           my %arg = @_;
1404 0           my @res;
1405              
1406 0           @res = $self->server_call(101, $arg{conf}, $arg{first}, $arg{count});
1407 0 0         if ($self->is_error(@res)) {
1408             return undef
1409 0           } else {
1410 0           shift @res;
1411 0     0     return parse_array_stream(sub{Net::Lyskom::Member->new_from_stream(@_)}, \@res)
  0            
1412             }
1413             }
1414              
1415             =item add_member(conf => $conf, pers => $pers_no, priority => $prio, where => $where, invitation => $invite, passive => $pass, secret => $secret)
1416              
1417             Add person number C as a member of conference number C, at
1418             priority C and at position C. C,
1419             C and C specify the membership type.
1420              
1421             =cut
1422              
1423             sub add_member {
1424 0     0 1   my $self = shift;
1425 0           my %arg = @_;
1426              
1427 0 0         my $type = sprintf "%s%s%s00000",
    0          
    0          
1428             ($arg{invitation}?"1":"0"),
1429             ($arg{passive}?"1":"0"),
1430             ($arg{secret}?"1":"0");
1431 0           return $self->gen_call_boolean(100, $arg{conf}, $arg{pers},
1432             $arg{priority}, $arg{where}, $type);
1433             }
1434              
1435             =item query_read_texts($pers, $conf)
1436              
1437             Return information on which texts person $pers has read in conference
1438             $conf. Returns an C object.
1439              
1440             =cut
1441              
1442             sub query_read_texts {
1443 0     0 1   my $self = shift;
1444 0           my ($pers, $conf) = @_;
1445              
1446 0           my @res = $self->server_call(98,$pers,$conf);
1447 0 0         if ($self->is_error(@res)) {
1448             return undef
1449 0           } else {
1450 0           shift @res;
1451 0           return Net::Lyskom::Membership->new_from_stream(\@res)
1452             }
1453             }
1454              
1455             =item set_expire($conf, $expire)
1456              
1457             Set the garb-nice value for conference C<$conf> to C<$expire>.
1458              
1459             =cut
1460              
1461             sub set_expire {
1462 0     0 1   my $self = shift;
1463 0           my ($conf, $expire) = @_;
1464              
1465 0           return $self->gen_call_boolean(97, $conf, $expire);
1466             }
1467              
1468             =item mark_text($text, $mark)
1469              
1470             Sets a mark of (numerical) type C<$mark> on text number C<$text>.
1471              
1472             =cut
1473              
1474             sub mark_text {
1475 0     0 1   my $self = shift;
1476 0           my ($text, $mark) = @_;
1477              
1478 0           return $self->gen_call_boolean(72, $text, $mark);
1479             }
1480              
1481             =item get_marks
1482              
1483             Returns an array of (text_no, mark_type) pairs, showing the texts the
1484             current user has marked.
1485              
1486             =cut
1487              
1488             sub get_marks {
1489 0     0 1   my $self = shift;
1490              
1491 0           my @res = $self->server_call(23);
1492 0 0         if ($self->is_error(@res)) {
1493 0           return undef;
1494             } else {
1495 0           shift @res;
1496 0     0     return parse_array_stream(sub{[splice @{$_[0]},0,2]},\@res);
  0            
  0            
1497             }
1498             }
1499              
1500             =item unmark_text($text)
1501              
1502             Remove any marks on the specified text.
1503              
1504             =cut
1505              
1506             sub unmark_text {
1507 0     0 1   my $self = shift;
1508 0           my $text = shift;
1509              
1510 0           return $self->gen_call_boolean(73, $text);
1511             }
1512              
1513             =item set_last_read($conf,$local_no)
1514              
1515             Tell the server that the current user has read everything up to local
1516             number C<$local_no> in conference number C<$conf>.
1517              
1518             =cut
1519              
1520             sub set_last_read {
1521 0     0 1   my $self = shift;
1522 0           my ($conf, $local_no) = @_;
1523              
1524 0           return $self->gen_call_boolean(77, $conf, $local_no)
1525             }
1526              
1527             =item set_conf_type(conf => $conf, rd_prot => $rp, original => $orig, secret => $sec, letterbox => $letter, allow_anonymous => $anon, forbid_secret => $nosecret)
1528              
1529             Set the type of conference C. C is required, the rest
1530             default to false if not specified.
1531              
1532             =cut
1533              
1534             sub set_conf_type {
1535 0     0 1   my $self = shift;
1536 0           my %arg = @_;
1537              
1538 0 0         die unless exists($arg{conf});
1539 0 0         $arg{rd_prot} = 0 unless $arg{rd_prot};
1540 0 0         $arg{original} = 0 unless $arg{original};
1541 0 0         $arg{secret} = 0 unless $arg{secret};
1542 0 0         $arg{letterbox} = 0 unless $arg{letterbox};
1543 0 0         $arg{allow_anonymous} = 0 unless $arg{allow_anonymous};
1544 0 0         $arg{forbid_secret} = 0 unless $arg{forbid_secret};
1545              
1546 0 0         my $type = sprintf "%s%s%s%s%s%s000",
    0          
    0          
    0          
    0          
    0          
1547             ($arg{rd_prot}?"1":"0"),
1548             ($arg{original}?"1":"0"),
1549             ($arg{secret}?"1":"0"),
1550             ($arg{letterbox}?"1":"0"),
1551             ($arg{allow_anonymous}?"1":"0"),
1552             ($arg{forbid_secret}?"1":"0");
1553 0           return $self->gen_call_boolean(21, $arg{conf}, $type);
1554              
1555             }
1556              
1557             =item mark_as_read($conf, @texts)
1558              
1559             Marks the texts specified by the local text numbers in C<@texts> as
1560             read in the conference C<$conf>.
1561              
1562             =cut
1563              
1564             sub mark_as_read {
1565 0     0 1   my $self = shift;
1566 0           my $conf = shift;
1567 0           my @texts = @_;
1568              
1569 0           return $self->gen_call_boolean(27, $conf, scalar @texts, '{', @texts, '}');
1570             }
1571              
1572             =item sub_comment($text, $comment)
1573              
1574             Removes C<$text> from C<$comment>s list of comments.
1575              
1576             =cut
1577              
1578             sub sub_comment {
1579 0     0 1   my $self = shift;
1580 0           my ($text, $comment) = @_;
1581              
1582 0           return $self->gen_call_boolean(33, $text, $comment);
1583             }
1584              
1585             =item add_footnote($text, $footnote_to)
1586              
1587             Makes text number C<$text> be a footnote to text number C<$footnote_to>.
1588              
1589             =cut
1590              
1591             sub add_footnote {
1592 0     0 1   my $self = shift;
1593 0           my ($text, $footnote_to) = @_;
1594              
1595 0           return $self->gen_call_boolean(37, $text, $footnote_to);
1596             }
1597              
1598             =item sub_footnote($text, $footnote_to)
1599              
1600             Makes text number C<$text> not be a footnote to text number C<$footnote_to>.
1601              
1602             =cut
1603              
1604             sub sub_footnote {
1605 0     0 1   my $self = shift;
1606 0           my ($text, $footnote_to) = @_;
1607              
1608 0           return $self->gen_call_boolean(38, $text, $footnote_to);
1609             }
1610              
1611             =item disconnect($session)
1612              
1613             Make session number C<$session> lose its connection with the server,
1614             given sufficient privilege. Session zero is always interpreted as the
1615             current session.
1616              
1617             =cut
1618              
1619             sub disconnect {
1620 0     0 1   my $self = shift;
1621 0           my $session = shift;
1622              
1623 0           return $self->gen_call_boolean(55, $session);
1624             }
1625              
1626             =item set_user_area($pers_no, $text_no)
1627              
1628             Make text number C<$text_no> be the user area for user number C<$pers_no>.
1629              
1630             =cut
1631              
1632             sub set_user_area {
1633 0     0 1   my $self = shift;
1634 0           my ($pers, $text) = @_;
1635              
1636 0           return $self->gen_call_boolean(57, $pers, $text);
1637             }
1638              
1639             =item get_uconf_stat($conf)
1640              
1641             Get a subset of all information for conference number C<$conf>.
1642             Returns a L object with only some fields
1643             filled.
1644              
1645             =cut
1646              
1647             sub get_uconf_stat {
1648 0     0 1   my $self = shift;
1649 0           my @confno = @_;
1650 0           my @res;
1651             my @tmp;
1652              
1653 0           @tmp = $self->server_call([map {[78,$_]} @confno]);
  0            
1654 0           foreach (@tmp) {
1655 0 0         if ($self->is_error(@{$_})) {
  0            
1656 0           push @res,undef;
1657             } else {
1658 0           shift @{$_}; # Remove return code
  0            
1659 0           push @res, Net::Lyskom::Conference->new_from_ustream($_);
1660             }
1661             }
1662              
1663 0 0         if (wantarray) {
1664 0           return @res;
1665             } else {
1666 0           return $res[0];
1667             }
1668             }
1669              
1670             =item set_info(conf_pres_conf => $cpc, pers_pres_conf => $ppc, motd_conf => $mc, kom_news_conf => $knc, motd_of_lyskom => $mol)
1671              
1672             Sets server information.
1673              
1674             =cut
1675              
1676             sub set_info {
1677 0     0 1   my $self = shift;
1678 0           my %arg = @_;
1679              
1680 0 0         $arg{conf_pres_conf} = 0 unless $arg{conf_pres_conf};
1681 0 0         $arg{pers_pres_conf} = 0 unless $arg{pers_pres_conf};
1682 0 0         $arg{motd_conf} = 0 unless $arg{motd_conf};
1683 0 0         $arg{kom_news_conf} = 0 unless $arg{kom_news_conf};
1684 0 0         $arg{motd_of_lyskom} = 0 unless $arg{motd_of_lyskom};
1685              
1686 0           return $self->gen_call_boolean(79, 0, # The zero must be there, see prot-a
1687             $arg{conf_pres_conf},
1688             $arg{pers_pres_conf},
1689             $arg{motd_conf},
1690             $arg{kom_news_conf},
1691             $arg{motd_of_lyskom}
1692             );
1693             }
1694              
1695             =item accept_async(@call_numbers)
1696              
1697             Tell the server to send the asynchronous calls with the numbers
1698             specified in C<@call_numbers>.
1699              
1700             =cut
1701              
1702             sub accept_async {
1703 0     0 1   my $self = shift;
1704              
1705 0           return $self->gen_call_boolean(80, scalar @_, '{', @_, '}');
1706             }
1707              
1708             =item query_async
1709              
1710             Ask server which asynchronous calls are turned on for this session.
1711             Returns a list of integers.
1712              
1713             =cut
1714              
1715             sub query_async {
1716 0     0 1   my $self = shift;
1717              
1718 0           my @res = $self->server_call(81);
1719 0 0         if ($self->is_error(@res)) {
1720             return undef
1721 0           } else {
1722 0     0     return parse_array_stream(sub{shift @{$_[0]}},\@res);
  0            
  0            
1723             }
1724             }
1725              
1726             =item get_collate_table
1727              
1728             Get the active collate table from the server.
1729              
1730             =cut
1731              
1732             sub get_collate_table {
1733 0     0 1   my $self = shift;
1734              
1735 0           return $self->gen_call_scalar(85);
1736             }
1737              
1738             =item create_anonymous_text(...arguments...)
1739              
1740             Exactly the same as C, except that it uses the call to
1741             create the text anonymously.
1742              
1743             =cut
1744              
1745             sub create_anonymous_text {
1746 0     0 1   my $self = shift;
1747 0           my %arg = @_;
1748 0           my @misc;
1749 0           my $misc_count = 0;
1750 0           my @aux;
1751 0           my $aux_count = 0;
1752 0           my @call;
1753              
1754 0           push @call, holl($arg{subject}."\n".$arg{body});
1755 0 0         if ($arg{recpt}) {
1756 0           foreach (@{$arg{recpt}}) {
  0            
1757 0           push @misc, 0, $_;
1758 0           $misc_count++;
1759             }
1760             }
1761 0 0         if ($arg{cc_recpt}) {
1762 0           foreach (@{$arg{cc_recpt}}) {
  0            
1763 0           push @misc, 1, $_;
1764 0           $misc_count++;
1765             }
1766             }
1767 0 0         if ($arg{bcc_recpt}) {
1768 0           foreach (@{$arg{bcc_recpt}}) {
  0            
1769 0           push @misc, 15, $_;
1770 0           $misc_count++;
1771             }
1772             }
1773 0 0         if ($arg{comm_to}) {
1774 0           foreach (@{$arg{comm_to}}) {
  0            
1775 0           push @misc, 2, $_;
1776 0           $misc_count++;
1777             }
1778             }
1779 0 0         if ($arg{footn_to}) {
1780 0           foreach (@{$arg{footn_to}}) {
  0            
1781 0           push @misc, 4, $_;
1782 0           $misc_count++;
1783             }
1784             }
1785 0           push @call, $misc_count, '{', @misc, '}';
1786              
1787 0 0         if ($arg{aux}) {
1788 0           foreach (@{$arg{aux}}) {
  0            
1789 0           push @aux, $_->to_server;
1790 0           $aux_count++;
1791             }
1792             }
1793 0           push @call, $aux_count, '{', @aux, '}';
1794              
1795 0           return $self->gen_call_scalar(87, @call);
1796             }
1797              
1798             =item create_conf(name => $name, rd_prot => $rp, original => $orig, secret => $sec, letterbox => $letter, allow_anonymous => $anon, forbid_secret => $nosecret, aux => $aux_array_ref)
1799              
1800             Create a conference.
1801              
1802             =cut
1803              
1804             sub create_conf {
1805 0     0 1   my $self = shift;
1806 0           my %arg = @_;
1807              
1808 0 0         croak "Tried to create conference with no name" unless $arg{name};
1809 0 0         $arg{rd_prot} = 0 unless $arg{rd_prot};
1810 0 0         $arg{original} = 0 unless $arg{original};
1811 0 0         $arg{secret} = 0 unless $arg{secret};
1812 0 0         $arg{letterbox} = 0 unless $arg{letterbox};
1813 0 0         $arg{allow_anonymous} = 0 unless $arg{allow_anonymous};
1814 0 0         $arg{forbid_secret} = 0 unless $arg{forbid_secret};
1815 0 0         $arg{aux} = [] unless $arg{aux};
1816              
1817 0 0         my $type = sprintf "%s%s%s%s%s%s000",
    0          
    0          
    0          
    0          
    0          
1818             ($arg{rd_prot}?"1":"0"),
1819             ($arg{original}?"1":"0"),
1820             ($arg{secret}?"1":"0"),
1821             ($arg{letterbox}?"1":"0"),
1822             ($arg{allow_anonymous}?"1":"0"),
1823             ($arg{forbid_secret}?"1":"0");
1824              
1825 0           return $self->gen_call_scalar(88,
1826             holl($arg{name}),
1827             $type,
1828 0 0         scalar @{$arg{aux}},
1829             '{',
1830 0           map ({$_ and $_->to_server} @{$arg{aux}}),
  0            
1831             '}'
1832             );
1833             }
1834              
1835             =item create_person(name => $name, password => $pwd, unread_is_secret => $uis, aux => $aux_array_ref)
1836              
1837             Create a person.
1838              
1839             =cut
1840              
1841             sub create_person {
1842 0     0 1   my $self = shift;
1843 0           my %arg = @_;
1844              
1845 0 0         croak "Tried to create person without name" unless $arg{name};
1846 0 0         croak "Tried to create person without password" unless $arg{password};
1847 0 0         $arg{unread_is_secret} = 0 unless $arg{unread_is_secret};
1848 0 0         $arg{aux} = [] unless $arg{aux};
1849 0 0         my $type = sprintf "%s0000000", ($arg{unread_is_secret}?"1":"0");
1850              
1851 0           return $self->gen_call_scalar(89,
1852             holl($arg{name}),
1853             holl($arg{password}),
1854             $type,
1855 0 0         scalar @{$arg{aux}},
1856             '{',
1857 0           map ({$_ and $_->to_server} @{$arg{aux}}),
  0            
1858             '}'
1859             );
1860             }
1861              
1862             =item modify_conf_info(conf => $conf, delete => $del_array_ref, add => $add_array_ref)
1863              
1864             Delete and/or add aux items to a conference. C<$del_array_ref> is a
1865             reference to an array of aux item numbers to delete. C<$add_array_ref>
1866             is a reference to an array of aux items to add.
1867              
1868             =cut
1869              
1870             sub modify_conf_info {
1871 0     0 1   my $self = shift;
1872 0           my %arg = @_;
1873              
1874 0 0         $arg{delete} = [] unless $arg{delete};
1875 0 0         $arg{add} = [] unless $arg{add};
1876              
1877 0 0         return undef unless $arg{conf};
1878 0           return $self->gen_call_boolean(93, $arg{conf},
1879 0           scalar @{$arg{delete}},
1880 0           '{',@{$arg{delete}},'}',
1881 0           scalar @{$arg{add}},
1882 0           '{', map {$_->to_server} @{$arg{add}},'}'
  0            
1883             );
1884             }
1885              
1886             =item modify_system_info(delete => $del_array_ref, add => $add_array_ref)
1887              
1888             Add and/or delete aux items for the server itself. Similar arguments
1889             as above.
1890              
1891             =cut
1892              
1893             sub modify_system_info {
1894 0     0 1   my $self = shift;
1895 0           my %arg = @_;
1896              
1897 0 0         $arg{delete} = [] unless $arg{delete};
1898 0 0         $arg{add} = [] unless $arg{add};
1899              
1900 0           return $self->gen_call_boolean(95,
1901 0           scalar @{$arg{delete}},
1902 0           '{',@{$arg{delete}},'}',
1903 0           scalar @{$arg{add}},
1904 0           '{', map {$_->to_server} @{$arg{add}},'}'
  0            
1905             );
1906              
1907             }
1908              
1909             =item set_keep_commented($conf, $keep)
1910              
1911             Set the C field for conference number C<$conf> to C<$keep>.
1912              
1913             =cut
1914              
1915             sub set_keep_commented {
1916 0     0 1   my $self = shift;
1917 0           my ($conf, $keep) = @_;
1918              
1919 0           return $self->gen_call_boolean(105, $conf, $keep);
1920             }
1921              
1922             =item set_pers_flags(person => $pers, unread_is_secret => $uis)
1923              
1924             Set the personal flags for person number C. At the moment
1925             there is only one such flag, but this method uses the many-args
1926             calling convention for ease of future expansion.
1927              
1928             =cut
1929              
1930             sub set_pers_flags {
1931 0     0 1   my $self = shift;
1932 0           my %arg = @_;
1933 0 0         my $type = sprintf "%s0000000", ($arg{unread_is_secret}?"1":"0");
1934              
1935 0           return $self->gen_call_boolean(106, $arg{person}, $type);
1936             }
1937              
1938             =item get_info
1939              
1940             Get the server info. Returns a C object.
1941              
1942             =cut
1943              
1944             sub get_info {
1945 0     0 1   my $self = shift;
1946              
1947 0           my @res = $self->server_call(94);
1948 0 0         if ($self->is_error(@res)) {
1949 0           return undef;
1950             } else {
1951 0           return Net::Lyskom::Info->new_from_stream(\@res);
1952             }
1953             }
1954              
1955             =back
1956              
1957             =cut
1958              
1959             # Return something true
1960             1;
1961              
1962             __END__