ad7c6707c64ecbba10f7baba7ef5cd6d5fb8d095
[citadel.git] / ctdlphp / ctdlprotocol.php
1 <?PHP
2 // $Id$
3 // 
4 // Implements various Citadel server commands.
5 //
6 // Copyright (c) 2003 by Art Cancro <ajc@uncensored.citadel.org>
7 // One program is released under the terms of the GNU General Public License.
8 include "config_ctdlclient.php";
9 //
10 // serv_gets() -- generic function to read one line of text from the server
11 //
12 function serv_gets($readblock=FALSE) {
13         global $clientsocket;
14
15         $buf = fgets($clientsocket, 4096);              // Read line
16         $buf = substr($buf, 0, (strlen($buf)-1) );      // strip trailing LF
17         if (CITADEL_DEBUG_CITPROTO == 1) {
18                 if (!$readblock) printf ("<div class='ctdldbgRead'>");
19                 printf($buf);
20                 if (!$readblock) printf ("</div>");
21                 else printf ("<br>");
22         }
23         return $buf;
24 }
25
26
27 //
28 // serv_puts() -- generic function to write one line of text to the server
29 //
30 function serv_puts($buf) {
31         global $clientsocket;
32         
33         fwrite($clientsocket, $buf . "\n", (strlen($buf)+1) );
34         fflush($clientsocket);
35         if (CITADEL_DEBUG_CITPROTO == 1)
36                 printf ("<div class='ctdldbgWrite'>".$buf."</div>");
37 }
38
39 function read_array() {
40         $nLines = 0;
41         if (CITADEL_DEBUG_CITPROTO == 1)
42             printf ("<div class='ctdldbgRead'>");
43         $buf = serv_gets(TRUE);
44         $ret = array();
45         while (strcasecmp($buf, "000")){
46                 array_push($ret, $buf);
47                 $buf = serv_gets(TRUE);
48                 $nLines++;
49         }
50         if (CITADEL_DEBUG_CITPROTO == 1){
51                 echo "read ".$nLines." lines from the server.";
52                 printf ("</div>");
53         }
54         return $ret;
55 }
56
57
58
59 // 
60 // text_to_server() -- sends a block of text to the server.  Assumes that
61 //                     the server just sent back a SEND_LISTING response code
62 //                     and is now expecting a 000-terminated series of lines.
63 //                     Set 'convert_to_html' to TRUE to convert the block of
64 //                     text to HTML along the way.
65 //
66 function text_to_server($thetext, $convert_to_html) {
67
68         // HTML mode
69         if ($convert_to_html) {
70
71                 // Strip CR's; we only want the LF's
72                 $thetext = trim($thetext, "\r");
73
74                 // Replace hard line breaks with <BR>'s
75                 $thetext = str_replace("\n", "<BR>\n", $thetext);
76
77         }
78
79         // Either mode ... send it to the server now
80         $one_line = strtok($thetext, "\n");
81         while ($one_line !== FALSE) {
82                 $one_line = trim($one_line, "\n\r");
83                 if ($one_line == "000") $one_line = "-000" ;
84                 serv_puts($one_line);
85                 $one_line = strtok("\n");
86         }
87
88         serv_puts("000");       // Tell the server we're done...
89
90         serv_puts("ECHO echo test.");           // FIXME
91         echo "Echo test: " . serv_gets() . "<BR>\n" ;
92
93 }
94
95 //
96 // Identify ourselves to the Citadel server (do one once after connection)
97 //
98 function ctdl_iden($client_info) {
99         global $clientsocket;
100
101         if (count($client_info) != 5)
102                 die("ctdl_iden takes 5 arguments!");
103         // Identify client and hostname
104         serv_puts("IDEN ".implode('|', $client_info));
105         $buf = serv_gets();
106 }
107
108 function ctdl_MessageFormatsPrefered($formatlist){
109         // Also express our message format preferences
110         serv_puts("MSGP ".implode("|", $formatlist));
111         $buf = serv_gets();
112 }
113
114
115
116 //
117 // login_existing_user() -- attempt to login using a supplied username/password
118 // Returns an array with two variables:
119 // 0. TRUE or FALSE to determine success or failure
120 // 1. String error message (if relevant)
121 //
122 function login_existing_user($user, $pass) {
123         global $clientsocket;
124
125         serv_puts("USER " . $user);
126         $resp = serv_gets();
127         if (substr($resp, 0, 1) != "3") {
128                 return array(FALSE, substr($resp, 4));
129         }
130
131         serv_puts("PASS " . $pass);
132         $resp = serv_gets();
133         if (substr($resp, 0, 1) != "2") {
134                 return array(FALSE, substr($resp, 4));
135         }
136
137         $_SESSION["username"] = $user;
138         $_SESSION["password"] = $pass;
139         become_logged_in(substr($resp, 4));
140
141         return array(TRUE, "Login successful.  Have fun.");
142 }
143
144
145 //
146 // create_new_user() -- attempt to create a new user 
147 //                      using a supplied username/password
148 // Returns an array with two variables:
149 // 0. TRUE or FALSE to determine success or failure
150 // 1. String error message (if relevant)
151 //
152 function create_new_user($user, $pass) {
153         global $clientsocket;
154
155         serv_puts("NEWU " . $user);
156         $resp = serv_gets();
157         if (substr($resp, 0, 1) != "2") {
158                 return array(FALSE, substr($resp, 4));
159         }
160
161         serv_puts("SETP " . $pass);
162         $resp = serv_gets();
163         if (substr($resp, 0, 1) != "2") {
164                 return array(FALSE, substr($resp, 4));
165         }
166
167         $_SESSION["username"] = $user;
168         $_SESSION["password"] = $pass;
169         become_logged_in(substr($resp, 4));
170
171         return array(TRUE, "Login successful.  Have fun.");
172 }
173
174
175 //
176 // Code common to both existing-user and new-user logins
177 //
178 function become_logged_in($server_parms) {
179         $_SESSION["logged_in"] = 1;
180
181         $tokens = explode("|", $server_parms);
182         
183         $oneline["username"]   = $tokens[0];
184         $oneline["axlevel"]    = $tokens[1];
185         $oneline["calls"]      = $tokens[2];
186         $oneline["posts"]      = $tokens[3];
187         $oneline["userflags"]  = $tokens[4];
188         $oneline["usernum"]    = $tokens[5];
189         $oneline["lastcall"]   = $tokens[6];
190                 
191         ctdl_goto("_BASEROOM_");
192 }
193
194
195
196 //
197 // Learn all sorts of interesting things about the Citadel server to
198 // which we are connected.
199 //
200 function ctdl_get_serv_info() {
201         serv_puts("INFO");
202         $reply = read_array();
203         if ((count($reply) == 18) &&
204             substr($reply[0], 0, 1) == "1") {
205                 $server_info=array();
206                 $server_info["serv_nodename"]  = $reply[1];
207                 $server_info["serv_humannode"] = $reply[2];
208                 $server_info["serv_fqdn"]      = $reply[3];
209                 $server_info["serv_software"]  = $reply[4];
210                 $server_info["serv_city"]      = $reply[6];
211                 $server_info["serv_sysadmin"]  = $reply[7];
212                 if (CITADEL_DEBUG_CITPROTO == 1)
213                 {
214                         echo "<pre>";
215                         print_r($server_info);
216                         echo "</pre>";
217                 }
218                 return $server_info;
219         }
220         else 
221                 die ("didn't understand the reply to the INFO command");
222
223 }
224
225
226 //
227 // Display a system banner.  (Returns completed HTML.)
228 // (One is probably temporary because it outputs more or less finalized
229 // markup.  For now it's just usable.)
230 //
231 function ctdl_mesg($msgname) {
232         global $clientsocket;
233
234         $msgtext = "<DIV ALIGN=CENTER>\n";
235
236         serv_puts("MESG " . $msgname);
237         $response = read_array();
238
239         if (substr($response[0], 0, 1) == "1") {
240                 array_shift($response); // throw away the status code.
241                 $msgtext .= "<TT>" . implode( "</TT><BR>\n" ,$response);
242         }
243         else {
244                 $msgtext .= "<B><I>" . substr($response[0], 4) . "</I></B><BR>\n";
245         }
246
247         $msgtext .= "</DIV>\n";
248         return($msgtext);
249 }
250
251
252 //
253 // Fetch the list of users currently logged in.
254 //
255 function ctdl_rwho() {
256         global $clientsocket;
257
258         serv_puts("RWHO");
259         $response = serv_gets();
260
261         if (substr($response, 0, 1) != "1") {
262                 return array(0, NULL);
263         }
264         
265         $all_lines = array();
266         $num_lines = 0;
267         
268         $responses = read_array();
269         foreach ($responses as $response) {
270                 $tokens = explode("|", $response);
271                 $oneline = array();
272
273                 $oneline["session"]      = $tokens[0];          
274                 $oneline["user"]         = $tokens[1];          
275                 $oneline["room"]         = $tokens[2];          
276                 $oneline["host"]         = $tokens[3];          
277                 $oneline["client"]       = $tokens[4];
278                 $oneline["idlesince"]    = $tokens[5];
279                 $oneline["lastcmd"]      = $tokens[6];
280                 $oneline["flags"]        = $tokens[7];
281                 $oneline["realname"]     = $tokens[8];
282                 $oneline["realroom"]     = $tokens[9];
283                 $oneline["realhostname"] = $tokens[10];
284                 $oneline["registered"]   = $tokens[11];
285
286                 // IGnore the rest of the fields for now.
287                 if (CITADEL_DEBUG_CITPROTO == 1)
288                 {
289                         echo "<pre>";
290                         print_r($oneline);
291                         echo "</pre>";
292
293                 }
294
295
296                 $num_lines = array_push($all_lines, $oneline);
297         }
298
299         return array($num_lines, $all_lines);
300
301 }
302
303
304 //
305 // Goto a room.
306 //
307 function ctdl_goto($to_where) {
308         
309         serv_puts("GOTO " . $to_where);
310         $response = serv_gets();
311
312         $results = explode ("|", $response);
313         $status_room = array_shift($results);
314         $status = substr($status_room, 0, 3);
315         if (substr($status, 0, 1) == "2") {
316                 $room = substr($status_room, 4);
317                 array_unshift($results, $room);
318                 $room_state=array(
319                         "state"          => TRUE,
320                         "statereply"     => $status,
321                         "roomname"       => $results[ 0],
322                         "nunreadmsg"     => $results[ 1],
323                         "nmessages"      => $results[ 2],
324                         "rinfopresent"   => $results[ 3],
325                         "flags"          => $results[ 4],
326                         "msgidmax"       => $results[ 5],
327                         "msgidreadmax"   => $results[ 6],
328                         "ismailroom"     => $results[ 7],
329                         "isroomaide"     => $results[ 8],
330                         "nnewmessages"   => $results[ 9],
331                         "floorid"        => $results[10],
332                         "viewselected"   => $results[11],
333                         "defaultview"    => $results[12],
334                         "istrashcan"     => $results[13]);
335                         
336                 $_SESSION["room"] = $room;
337                 if (CITADEL_DEBUG_CITPROTO == 1)
338                 {
339                         echo "<pre>";
340                         print_r($room_state);
341                         echo "</pre>";
342
343                 }
344
345                 return $room_state;
346         }
347
348         else {
349                 return array("state" => FALSE, "statereply" => $status);
350         }
351
352 }
353
354
355
356 //
357 // Fetch the list of known rooms.
358 //
359 function ctdl_knrooms() {
360         global $clientsocket;
361
362         serv_puts("LKRA");
363         $results = read_array();
364
365         if (substr($results[0], 0, 1) != "1") {
366                 return array(0, NULL);
367         }
368         array_shift($results);
369         $all_lines = array();
370         $num_lines = 0;
371
372         foreach ($results as $result){
373                 $oneline = array();
374                 $tokens = explode("|",$result);
375
376                 $oneline["name"]   = $tokens[0];                
377                 $oneline["flags"]  = $tokens[1];                
378                 $oneline["floor"]  = $tokens[2];                
379                 $oneline["order"]  = $tokens[3];                
380                 $oneline["flags2"] = $tokens[4];                
381                 $oneline["access"] = $tokens[5];
382
383                 if ($oneline["access"] & 8) {
384                         $oneline["hasnewmsgs"] = TRUE;
385                 }
386                 else {
387                         $oneline["hasnewmsgs"] = FALSE;
388                 }
389
390                 if (CITADEL_DEBUG_CITPROTO == 1)
391                 {
392                         echo "<pre>";
393                         print_r($oneline);
394                         echo "</pre>";
395
396                 }
397                 $num_lines = array_push($all_lines, $oneline);
398         }
399
400         return array($num_lines, $all_lines);
401
402 }
403
404
405 //
406 // Fetch the list of messages in one room.
407 // Returns: count, response, message array
408 //
409 function ctdl_msgs($mode, $count) {
410         global $clientsocket;
411
412         serv_puts("MSGS " . $mode . "|" . $count);
413         $responses = read_array();
414         print_r($responses);
415
416         $response = array_shift($responses);
417
418         $num_msgs = count($responses);
419         if (substr($response, 0, 1) != "1") {
420                 return array(0, substr($response, 4), NULL);
421         }
422         
423         if (CITADEL_DEBUG_CITPROTO == 1)
424         {
425                 printf("found ".$num_msgs." messages.");
426         }
427         return array($num_msgs, $response, $responses);
428 }
429
430
431 // Load a message from the server.
432 function ctdl_fetch_message($msgnum) {
433         global $clientsocket;
434
435         serv_puts("MSG4 " . $msgnum);
436
437         if (CITADEL_DEBUG_CITPROTO == 1)
438             printf ("<div class='ctdldbgRead'>");
439         $response = serv_gets(TRUE);
440
441         if (substr($response, 0, 1) != "1") {
442                 return array(FALSE, substr($response, 4), NULL);
443         }
444
445         $fields = array();
446         while (strcmp($buf = serv_gets(TRUE), "000")) {
447                 if (substr($buf, 0, 4) == "text") {
448                         if (CITADEL_DEBUG_CITPROTO == 1)
449                                 printf ("</div>\n<h3>Message Body Follows</h3><div class='ctdldbgRead'>");
450                         // We're in the text body.  New loop here.
451                         $fields["text"] = ctdl_msg4_from_server();
452                         if (CITADEL_DEBUG_CITPROTO == 1)
453                                 printf ("</div>");
454                         return array(TRUE, substr($response, 4), $fields);
455                 }
456                 else {
457                         $fields[substr($buf, 0, 4)] = substr($buf, 5);
458                 }
459         }
460
461         // Message terminated prematurely (no text body)
462         return array(FALSE, substr($response, 4), $fields);
463 }
464
465 // Support function for ctdl_fetch_message(). This handles the text body
466 // portion of the message, converting various formats to HTML as
467 // appropriate.
468 function ctdl_msg4_from_server() {
469
470         $txt = "";
471         $msgformat = "text/plain";
472         $in_body = FALSE;
473
474         $previous_line = "";
475         while (strcmp($buf = serv_gets(TRUE), "000")) {
476                 if ($in_body == FALSE) {
477                         if (strlen($buf) == 0) {
478                                 $in_body = TRUE;
479                         }
480                         else {
481                                 if (!strncasecmp($buf, "content-type: ", 14)) {
482                                         $msgformat = substr($buf, 14);
483                                 }
484                         }
485                 }
486                 else {
487                         if (!strcasecmp($msgformat, "text/html")) {
488                                 $txt .= $buf;
489                         }
490                         else if (!strcasecmp($msgformat, "text/plain")) {
491                                 $txt .= "<TT>" . htmlspecialchars($buf) . "</TT><BR>\n" ;
492                         }
493                         else if (!strcasecmp($msgformat, "text/x-citadel-variformat")) {
494                                 if (substr($previous_line, 0, 1) == " ") {
495                                         $txt .= "<BR>\n" ;
496                                 }
497                                 $txt .= htmlspecialchars($buf);
498                         }
499                         else {
500                                 $txt .= htmlspecialchars($buf);
501                         }
502                         $previous_line = $buf;
503                 }
504         }
505
506         return($txt);
507 }
508
509
510 ?>