irc._pike
Go to the documentation of this file.
1 /* Copyright (C) 2000-2005 Thomas Bopp, Thorsten Hampel, Ludger Merkens
2  *
3  * This program is free software; you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License as published by
5  * the Free Software Foundation; either version 2 of the License, or
6  * (at your option) any later version.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16  *
17  * $Id: irc.pike,v 1.3 2010/01/27 12:05:35 astra Exp $
18  */
19 inherit "/net/coal/login";
20 inherit "/net/base/line";
21 inherit "/net/base/cmd";
22  inherit Events.Listener;
23 #include <macros.h>
24 #include <config.h>
25 #include <access.h>
26 #include <database.h>
27 #include <events.h>
28 #include <client.h>
29 #include <classes.h>
30 #include <attributes.h>
31 class irc : public login,line,cmd{
32 public:
33 
34 
35 
36 
37 
38 #define STATE_AUTHORIZATION 1
39 #define STATE_TRANSACTION 2
40 #define STATE_UPDATE 3
41 
42 
43 //#define IRC_DEBUG 1
44 
45 #ifdef IRC_DEBUG
46 #define DEBUG_IRC(s, args...) werror("IRC: " + s+"\n", args)
47 #else
48 #define DEBUG_IRC(s, args...)
49 #endif
50 
51 #define I_TIMEOUT 100
52 
53  string sServer = _Server->get_server_name();
54 
55  object oMailBox;
56  object oChannel;
57  string sNick;
58  string sUser;
59  string sChannel;
60  string sPass;
61 
62 class Dcc {
63 public:
64  Stdio.Port dcc_port;
65  int port_nr;
66  object doc;
67 };
68 
69 
70 class IrcListener {
71 public:
72 
73  void create(int events, object obj) {
74  ::create(events, PHASE_NOTIFY, obj, 0, oUser);
75  obj->listen_event(this_object());
76  }
77 
78  void notify(int event, mixed args, object eObject) {
79  mixed err = catch(notify_irc(event, @args));
80  DEBUG_IRC("Failed to notify in IRC: %O", err);
81  }
82  function get_callback() {
83  return notify;
84  }
85 
86  mapping save() { return 0; }
87 
88  string describe() {
89  return "IrcListener()";
90  }
91 }
92 
93  IrcListener roomListener;
94  IrcListener logoutListener;
95  IrcListener tellListener;
96 
97 #define RPL_AWAY 301
98 #define RPL_ISON 303
99 #define RPL_WHOISUSER 311
100 #define RPL_WHOISOPERATOR 313
101 #define RPL_WHOISIDLE 314
102 #define RPL_ENDOFWHO 315
103 #define RPL_ENDOFWHOIS 318
104 #define RPL_WHOISCHANNELS 319
105 
106 #define RPL_LISTSTART 321
107 #define RPL_LIST 322
108 #define RPL_LISTEND 323
109 #define RPL_WHOREPLY 352
110 #define RPL_NAMEREPLY 353
111 #define RPL_ENDOFNAMES 366
112 
113 #define RPL_MOTDSTART 375
114 #define RPL_MOTD 372
115 #define RPL_ENDOFMOTD 376
116 
117 #define RPL_USERSSTART 392
118 #define RPL_USERS 393
119 #define RPL_ENDOFUSERS 394
120 
121 #define ERR_NOSUCHNICK 401
122 #define ERR_NOSUCHSERVER 402
123 #define ERR_NOSUCHCHANNEL 403
124 #define ERR_CANNOTSENDTOCHAN 404
125 #define ERR_TOOMANYCHANNELS 405
126 #define ERR_WASNOSUCHNICK 406
127 #define ERR_TOOMANYTARGET 407
128 #define ERR_NORECIPIENT 411
129 #define ERR_UNKNOWNCOMMAND 421
130 
131 #define ERR_NICKCOLLISION 436
132 #define ERR_NOTONCHANNEL 442
133 
134 #define ERR_NEEDMOREPARAMS 461
135 #define ERR_PASSWDMISSMATCH 464
136 #define ERR_UNKNOWNMODE 472
137 #define ERR_INVITEONLYCHAN 473
138 
139 protected:
140  mapping mReplies = ([
141  ERR_NOSUCHNICK: "No such nick/channel",
142  ERR_PASSWDMISSMATCH: "Password incorrect",
143  ERR_NICKCOLLISION: "Nickname collision KILL",
144  RPL_ENDOFWHOIS: "End of /WHOIS list",
145  ERR_INVITEONLYCHAN: "Cannot join channel (+i)",
146  ERR_TOOMANYCHANNELS: "You have joined too many channels",
147  ERR_UNKNOWNMODE: "is unknown mode char to me",
148  RPL_USERSSTART: "UserID Terminal Host",
149  RPL_ENDOFUSERS: "End of users",
150  RPL_ENDOFWHO: "End of /WHO",
151  ]);
152 
153 protected:
154  void send_reply(string|int cmd, string|void|array params)
155 {
156  string trailing = 0;
157 
158  if ( arrayp(params) ) {
159  params = params * " ";
160  }
161  else if ( !stringp(params) )
162  params = "";
163 
164  LOG("Sending ok ("+cmd+")");
165  if ( intp(cmd) ) {
166  if ( stringp(mReplies[cmd]) )
167  trailing = mReplies[cmd];
168  if ( cmd < 10 )
169  cmd = "00" + cmd;
170  else if ( cmd < 100 )
171  cmd = "0" + cmd;
172  }
173  cmd = ":"+sServer+" "+ cmd + " " +
174  (objectp(oUser) ? " " + oUser->get_identifier() : "");
175  if ( stringp(trailing) ) {
176  params += ":"+trailing;
177  }
178 
179  if ( stringp(params) )
180  send_message(cmd + " " + params + "\r\n");
181  else
182  send_message(cmd + "\r\n");
183 }
184 
185 public:
186 
187 protected:
188  void send_myself(string msg)
189 {
190  send_message(cryptic_irc_name(oUser) + " PRIVMSG SERVER :" +msg+ "\r\n");
191 }
192 
193 public:
194 
195 int get_port()
196 {
197  string addr = query_address();
198  int port;
199  sscanf(addr, "%*s %d", port);
200  return port;
201 }
202 
203 void identd()
204 {
205  Stdio.File identsock = Stdio.File();
206  string ip = get_ip();
207  if ( stringp(ip) && identsock->connect(ip, 113) ) {
208  send_message(":"+sServer+
209  " NOTICE AUTH : *** Got Ident response\r\n");
210  string msg = _Server->query_config("irc_port")+","+
211  get_port()+"\r\n";
212  LOG("IDENTD:"+msg);
213  identsock->write(msg);
214  string str;
215 
216  int t = time();
217  while ( (time()-t) < I_TIMEOUT && (
218  !stringp(str=identsock->read()) || strlen(str) == 0) )
219  ;
220 
221  LOG("REPLIES:"+str);
222  send_message(":"+sServer+
223  " NOTICE AUTH : *** Found your hostname\r\n");
224  }
225 }
226 
227 void pinging()
228 {
229  while ( 1 ) {
230  sleep(120);
231  if ( catch(send_message("PING " + sServer + "\r\n")) )
232  return; // end thread when connection is down
233  }
234 }
235 
236 void create(object f)
237 {
238  ::create(f);
239  send_message(":"+sServer+
240  " NOTICE AUTH : *** Looking up your hostname...\r\n");
241  send_message(":"+sServer+" NOTICE AUTH : *** Checking Ident\r\n");
242 
243  //thread_create(identd);
244  thread_create(pinging);
245 
246  sClientClass = "irc";
247  oChannel = 0;
248 }
249 
250 
251 string cryptic_irc_name(object obj)
252 {
253  if ( !objectp(obj) )
254  return "none";
255 
256  if ( IS_SOCKET(obj) ) {
257  if ( !functionp(obj->get_socket_name) )
258  FATAL("No socket-name function in %O", obj);
259  else if ( obj->get_socket_name() == "irc" )
260  return ":"+obj->get_nick() + "!~"+obj->get_nick() + "@"+obj->get_ip();
261  obj = obj->get_user_object();
262  }
263  if ( !(obj->get_object_class() & CLASS_USER) )
264  return ":("+obj->get_identifier()+")!~"+obj->get_identifier() +"@"+sServer;
265 
266 
267  return ":"+obj->get_identifier() + "!~"+obj->get_identifier()+"@"+
268  obj->get_ip(CLIENT_FEATURES_CHAT);
269 }
270 
271 string channel_name(object obj)
272 {
273  string channel;
274 
275  if ( objectp(obj) ) {
276  channel = _FILEPATH->object_to_filename(obj);
277  if ( sscanf(channel, "/home/%s", channel) > 0 )
278  channel = "&" + replace(channel," ", "^");
279  else
280  channel = "#" + channel;
281  return channel;
282  }
283  return "";
284 }
285 
286 void notify_irc(int event, mixed ... args)
287 {
288  object user = geteuid() || this_user();
289  if ( !objectp(oUser) || !objectp(user) )
290  return;
291 
292  switch(event) {
293  case EVENT_SAY:
294  if ( user != oUser )
295  send_message(cryptic_irc_name(user) + " PRIVMSG " +
296  channel_name(args[0]) + " :" + args[2] +"\r\n");
297  break;
298  case EVENT_LOGIN|EVENTS_MONITORED:
299  if ( intp(args[4]) && (args[4] & CLIENT_FEATURES_CHAT) )
300  return; //previously had chat client active
301  if (intp(args[3]) && (args[3] & CLIENT_FEATURES_CHAT) )
302  send_message(cryptic_irc_name(user) + " JOIN " +
303  channel_name(user->get_environment())+"\r\n");
304  break;
305  case EVENT_ENTER_INVENTORY:
306  if ( user->get_object_class() & CLASS_USER &&
307  user->get_status() & CLIENT_FEATURES_CHAT )
308  send_message(cryptic_irc_name(user) + " JOIN " +
309  channel_name(args[0])+"\r\n");
310  break;
311  case EVENT_LOGOUT|EVENTS_MONITORED:
312  if ( user->get_object_class() & CLASS_USER )
313  send_message(cryptic_irc_name(user) + " PART " +
314  channel_name(args[0])+"\r\n");
315  break;
316  case EVENT_LEAVE_INVENTORY:
317  if ( user->get_object_class() & CLASS_USER &&
318  user->get_status() & CLIENT_FEATURES_CHAT )
319  send_message(cryptic_irc_name(user) + " PART " +
320  channel_name(args[0])+"\r\n");
321  break;
322  case EVENT_TELL:
323  send_message(cryptic_irc_name(user) + " PRIVMSG "+
324  args[0]->get_identifier() + " :"+args[2] + "\r\n");
325  break;
326  }
327 }
328 
329 object str_to_channel(string channel)
330 {
331  int chann;
332  if ( sscanf(channel, "#%d", chann) == 1 )
333  return find_object(chann);
334  else if ( channel[0] == '&' )
335  return _FILEPATH->path_to_object(
336  "/home/"+replace(channel[1..],"^"," "));
337  else
338  return _FILEPATH->path_to_object(channel[1..]);
339 }
340 
341 /*************************************************************************
342  * authorization, login stuff
343  */
344 
345 protected:
346  void pass(string p)
347 {
348  sPass = p;
349  if ( oUser == _GUEST )
350  {
351  if ( stringp(sNick) )
352  user(sNick);
353  }
354 }
355 
356 public:
357 
358 protected:
359  void welcome_user()
360 {
361  send_reply(1, ({ ":Welcome to the sTeam IRC network "+
362  cryptic_irc_name(oUser) }));
363  send_reply(2, ({ ":Your host is "+ get_ip() }));
364  send_reply(3, ({ ":This server was created " +
365  replace(ctime(_Server->get_last_reboot()),"\n","")}));
366  send_reply(4, ({ ":"+sServer+ " 1.0 steam users and channels " }) );
367  send_reply(RPL_MOTDSTART, ":- "+ sServer+
368  " Message of the day - ");
369  send_reply(RPL_MOTD, ":- sTeam IRC Server");
370  send_reply(RPL_MOTD, ":- Use your sTeam login as nick and");
371  send_reply(RPL_MOTD, ":- your user password as server password or /msg steam pass <pass>");
372  send_reply(RPL_MOTD, ":- Welcome! steam's workroom is default meeting place");
373  send_reply(RPL_ENDOFMOTD, ":End of /MOTD command");
374 }
375 
376 public:
377 
378 protected:
379  void connect_user(object u)
380 {
381  login_user(u);
382  welcome_user();
383  object channel = u->get_environment();
384  DEBUG_IRC("Connecting user, environment is %O\n", channel);
385  if ( objectp(channel) )
386  join(channel_name(channel));
387  if ( objectp(tellListener) )
388  destruct(tellListener);
389  tellListener = IrcListener(EVENT_TELL, u);
390 }
391 
392 public:
393 
394 protected:
395  void nick(string n)
396 {
397  sNick = n;
398 }
399 
400 public:
401 
402 protected:
403  void user(string u)
404 {
405  object user;
406 
407  sUser = u;
408  if ( !stringp(sPass) ) {
409  send_message(":sTeam!~steam@"+sServer+" PRIVMSG SERVER :" +
410  "Nickname " + sNick +
411  " needs pass, /msg sTeam pass <yourpass> to login !\r\n");
412  return;
413  }
414  user = get_module("auth")->authenticate(sNick, sPass);
415  if ( objectp(user) )
416  {
417  if ( objectp(oUser) ) {
418  login_user(user);
419  }
420  else {
421  connect_user(user);
422  }
423 
424  }
425  else {
426  send_reply(ERR_PASSWDMISSMATCH, sPass);
427  }
428  /* ERR_NICKNAMEINUSE ??? */
429 
430 }
431 
432 public:
433 
434 
435 protected:
436  void list(void|string param)
437 {
438  LOG("list(" + param+")");
439  array rooms = ({ });
440  array groups = MODULE_GROUPS->get_groups();
441  foreach(groups, object g) {
442  object r = g->query_attribute(GROUP_WORKROOM);
443  if ( objectp(r) )
444  rooms += ({ r });
445  }
446  send_reply(RPL_LISTSTART, "Channel: Users Name");
447  foreach(rooms, object room) {
448  string topic = room->query_attribute("irc:topic");
449  if ( !stringp(topic) )
450  topic = room->get_identifier();
451  send_reply(RPL_LIST, " "+channel_name(room)+ " " +
452  sizeof(get_users(room))+" :"+topic+"\r\n");
453  }
454  send_reply(RPL_LISTEND, ":End of /LIST");
455 }
456 
457 public:
458 
459 
460 
461 protected:
462  int join_channel(object channel)
463 {
464  mixed err = catch {
465  oUser->move(channel);
466  if ( objectp(roomListener) )
467  destruct(roomListener);
468  if ( objectp(logoutListener) )
469  destruct(logoutListener);
470 
471  roomListener = IrcListener(EVENT_SAY|EVENT_ENTER_INVENTORY|
472  EVENT_LEAVE_INVENTORY, channel);
473  logoutListener= IrcListener(EVENT_LOGIN|EVENT_LOGOUT|EVENTS_MONITORED,
474  channel);
475  };
476  return err == 0;
477 }
478 
479 public:
480 
481 protected:
482  void list_users(object channel)
483 {
484  array users = get_users(channel);
485  string user_str = "sTeam ";
486  foreach(users, object u) {
487  if ( u->get_status() & CLIENT_FEATURES_CHAT )
488  user_str += u->get_identifier() + " ";
489  }
490  send_reply(RPL_NAMEREPLY, " = " + channel_name(channel)+" :" +
491  user_str);
492  send_reply(RPL_ENDOFNAMES, ":End of /NAMES list.");
493 }
494 
495 public:
496 
497 protected:
498  array get_users(object channel)
499 {
500  array users = ({ });
501  object event = channel->get_event(EVENT_SAY);
502  array listeners = event->get_listeners();
503  foreach(listeners, object l) {
504  if ( !objectp(l) )
505  continue;
506  object u = l->get_listening();
507  if ( objectp(u) && u->get_status() & CLIENT_FEATURES_CHAT )
508  users += ({ u });
509  }
510  return users;
511 }
512 
513 public:
514 
515 protected:
516  void who(string channel)
517 {
518  array users = ({ });
519 
520  object chann = str_to_channel(channel);
521 
522  if ( objectp(chann) ) {
523  users = get_users(chann);
524  }
525  if ( sizeof(users) > 0 ) {
526  foreach(users, object user ) {
527  send_reply(RPL_WHOREPLY,
528  ({ channel_name(chann),
529  user->get_identifier(),
530  user->get_ip(CLIENT_FEATURES_CHAT),
531  _Server->get_server_name(),
532  user->get_identifier(),
533  "H",
534  ": 0 "+user->query_attribute(USER_FULLNAME) }));
535  }
536  send_reply(RPL_WHOREPLY,
537  ({ channel_name(chann),
538  "sTeam",
539  _Server->get_server_name(),
540  _Server->get_server_name(),
541  "sTeam",
542  "H",
543  ": 0 sTeam Server" }));
544  send_reply(RPL_ENDOFWHO);
545  }
546 }
547 
548 public:
549 
550 protected:
551  void join(string channels)
552 {
553  string keys = "";
554  array channs;
555 
556  sscanf(channels, "%s %s", channels, keys);
557  channs = channels / ",";
558 
559  object chann = str_to_channel(channs[0]);
560  if ( objectp(oChannel) && oChannel != chann ) {
561  send_message(cryptic_irc_name(oUser) + " PART "+
562  channel_name(oChannel)+"\r\n");
563  }
564 
565  if ( objectp(chann) ) {
566  if ( join_channel(chann) ) {
567  oChannel = chann;
568  string msg = cryptic_irc_name(oUser)+" JOIN "+
569  channel_name(chann)+"\r\n";
570  send_message(msg);
571  reply_topic(chann);
572  list_users(chann);
573  }
574  else {
575  DEBUG_IRC("Invite Only Channel Message returned ...");
576  send_reply(ERR_INVITEONLYCHAN, channs[0]);
577  }
578  }
579  else {
580  DEBUG_IRC("No such channel returned upon joining %s", channels);
581  send_reply(ERR_NOSUCHCHANNEL, channs[0]);
582  }
583 }
584 
585 public:
586 
587 protected:
588  void part(string channel)
589 {
590  object chann = str_to_channel(channel);
591  if ( objectp(chann) ) {
592  if ( chann == oChannel ) {
593  oChannel = 0;
594  send_message(cryptic_irc_name(oUser)+" PART "+
595  channel_name(chann)+"\r\n");
596  }
597  else
598  send_reply(ERR_NOTONCHANNEL, channel);
599  }
600  else
601  send_reply(ERR_NOSUCHCHANNEL, channel);
602 }
603 
604 public:
605 
606 void send_invite(string channel)
607 {
608  send_reply(324, ({ channel, "+i", oUser->get_identifier() }));
609  send_message(cryptic_irc_name(geteuid() || this_user()) + " INVITE "+oUser->get_identifier() + " "+channel+"\r\n");
610 }
611 
612 protected:
613  void invite(string user, string channel)
614 {
615  object chann = str_to_channel(channel);
616  if ( objectp(chann) ) {
617  // give the user permissions
618  object u = MODULE_USERS->lookup(user);
619  if ( objectp(u) ) {
620  chann->sanction_object(u, SANCTION_READ|SANCTION_ANNOTATE);
621  send_reply(341, ({ user, channel }));
622  array sockets = u->get_sockets();
623  foreach(sockets, object sock ) {
624  if ( sock->get_socket_name() == "irc" )
625  sock->send_invite(channel);
626  }
627  return;
628  }
629  send_reply(ERR_NOSUCHNICK);
630  }
631  send_reply(ERR_NOSUCHCHANNEL, channel);
632 }
633 
634 public:
635 
636 protected:
637  void ison(string userlist)
638 {
639  array rpl_user_list = ({ });
640  array ul = userlist / " ";
641  foreach(ul, string user) {
642  object u = MODULE_USERS->lookup(user);
643  if ( objectp(u) ) {
644  if (u->get_client_features() & CLIENT_FEATURES_CHAT) {
645  rpl_user_list += ({ user });
646  }
647  }
648  }
649  if (sizeof(rpl_user_list) > 0) {
650  rpl_user_list[0] = ":" + rpl_user_list[0];
651  }
652  send_reply(RPL_ISON, rpl_user_list);
653 }
654 
655 public:
656 
657 protected:
658  void mode(string channel, void|string m)
659 {
660  LOG("mode("+m+")");
661  if ( !stringp(m) || strlen(m) == 0 )
662  return;
663 
664  send_reply(ERR_UNKNOWNMODE);
665 }
666 
667 public:
668 
669 protected:
670  void reply_topic(object channel)
671 {
672  string channelstr, topic;
673  channelstr = channel_name(channel);
674  topic = channel->query_attribute("irc:topic");
675  if ( !stringp(topic) )
676  topic = channel->get_identifier();
677  send_reply(332, ({ channelstr, ":" + topic }));
678 }
679 
680 public:
681 
682 protected:
683  void topic(string channel, string topic)
684 {
685  LOG("topic("+topic+")");
686  if ( !stringp(topic) )
687  send_reply(ERR_NEEDMOREPARAMS, "topic");
688  object chann = str_to_channel(channel);
689  if ( objectp(chann) ) {
690  chann->set_attribute("irc:topic", topic);
691  reply_topic(chann);
692  }
693 }
694 
695 public:
696 
697 protected:
698  void exec_response(string res)
699 {
700  array result = res / "\n";
701  send_message(cryptic_irc_name(geteuid() || this_user()) + " PRIVMSG "+
702  _ROOT->get_identifier()+
703  " :---Result of execution---\r\n");
704  foreach(result, string r) {
705  send_message(cryptic_irc_name(geteuid() || this_user()) + " PRIVMSG "+
706  _ROOT->get_identifier()+" :"+r+"\r\n");
707  }
708 }
709 
710 public:
711 
712 protected:
713  void exec(string msg)
714 {
715  string res = execute("^" + msg);
716  exec_response(res);
717 }
718 
719 public:
720 
721 protected:
722  void establish_dcc(string ip, int port, string fname, int size)
723 {
724  object conn = Stdio.File();
725  DEBUG_IRC("establishing dcc to "+ip+"\n");
726  conn->connect(ip, port);
727  conn->set_buffer(200000);
728  string data, rd;
729  rd = "";
730  data = "";
731  while ( stringp(rd=conn->read(1024,1)) && strlen(rd) > 0 ) {
732  DEBUG_IRC("Read "+ strlen(rd) + " bytes...\n");
733  data += rd;
734  int sz = strlen(data);
735  string str = " ";
736  str[0] = (sz & ( 255 << 24)) >> 24;
737  str[1] = (sz & ( 255 << 16)) >> 16;
738  str[2] = (sz & ( 255 << 8)) >> 8;
739  str[3] = (sz & ( 255 ));
740  conn->write(str);
741  }
742  conn->close();
743  object doc = oChannel->get_object_byname(fname);
744  if ( !objectp(doc) ) {
745  object factory = get_factory(CLASS_DOCUMENT);
746  doc = factory->execute( ([ "name": fname, ]) );
747  doc->move(oChannel);
748  }
749  doc->set_content(data);
750 }
751 
752 public:
753 
754 protected:
755  void privmsg(string channel, string msg)
756 {
757  LOG("privmsg("+channel+","+msg+")");
758 
759  if ( lower_case(channel) == "steam" ) {
760  string cmd;
761 
762  if ( sscanf(msg, "\1%s %s\1", cmd, msg) != 2 &&
763  sscanf(msg, "%s %s", cmd, msg) != 2 )
764  cmd = "";
765  DEBUG_IRC("Command is "+ cmd+"\n");
766  switch ( cmd ) {
767  case "PASS":
768  case "pass":
769 #if 0
770  if ( oUser != _GUEST ) {
771  send_message(cryptic_irc_name(oUser) + " PRIVMSG NICKSERV :" +
772  "You are already registered as "+
773  oUser->get_identifier()+"\r\n");
774  return;
775  }
776 #endif
777  sPass = msg;
778  object u = get_module("auth")->authenticate(sNick, sPass);
779  if ( !objectp(u) )
780  send_message(cryptic_irc_name(oUser) + " PRIVMSG NICKSERV :"+
781  "User not found or wrong password !\r\n");
782  else
783  connect_user(u);
784  return;
785  case "DCC":
786  case "dcc":
787  int sz = 0;
788  array args = (msg / " ");
789  DEBUG_IRC("DCC="+sprintf("%O",args)+"\n");
790  if ( sizeof(args) > 4 )
791  sz = args[4];
792  if ( args[0] == "SEND" ) {
793  establish_dcc(get_ip(), (int)args[3], args[1], sz);
794  }
795  break;
796  case "LOG":
797  case "log":
798  object chatlog = get_module( "package:chatlog" );
799  if ( !objectp(chatlog) ) {
800  if ( stringp(channel) && sizeof(channel)>0 )
801  send_message( cryptic_irc_name(oUser) + " PRIVMSG " + channel +
802  " : Could not find chatlog module\r\n" );
803  return;
804  }
805  object room = oUser->get_environment();
806  if ( !objectp(room) ) {
807  if ( stringp(channel) && sizeof(channel)>0 )
808  send_message( cryptic_irc_name(oUser) + " PRIVMSG " + channel +
809  " : Invalid room for logging\r\n");
810  return;
811  }
812  switch ( msg ) {
813  case "list" :
814  case "LIST" :
815  {
816  send_message( cryptic_irc_name(oUser) + " PRIVMSG " + channel +
817  sprintf(" : Active chat-Logs: %O\r\n", chatlog->get_rooms()) );
818  }
819  break;
820  case "on" :
821  case "ON" :
822  {
823  int success;
824  mixed err = catch { success = chatlog->log_room( room, true ); };
825  object file = chatlog->get_logfile( room );
826  string filename = "";
827  if ( objectp(file) ) filename = sprintf( " to %s", get_module("filepath:tree")->object_to_filename(file) );
828  string result_msg = sprintf("Logging chat in room %s to file %s\r\n",
829  room->query_attribute(OBJ_NAME), filename );
830  if ( err ) result_msg = err[0];
831  else if ( !success ) result_msg = sprintf("Failed to turn on logging for room %s", room->query_attribute(OBJ_NAME));
832  send_message( cryptic_irc_name(oUser) + " PRIVMSG " + channel +
833  " : " + result_msg + "\r\n");
834  }
835  break;
836  case "off" :
837  case "OFF" :
838  {
839  int success;
840  object file = chatlog->get_logfile( room );
841  string filename = "";
842  if ( objectp(file) ) filename = sprintf( " to %s", get_module("filepath:tree")->object_to_filename(file) );
843  mixed err = catch { success = chatlog->log_room( room, 0 ); };
844  string result_msg = sprintf("Stopped logging chat in room %s to file %s\r\n",
845  room->query_attribute(OBJ_NAME), filename );
846  if ( err ) result_msg = err[0];
847  else if ( !success ) result_msg = sprintf("Failed to turn off logging for room %s", room->query_attribute(OBJ_NAME));
848  send_message( cryptic_irc_name(oUser) + " PRIVMSG " + channel +
849  " : " + result_msg + "\r\n");
850  }
851  break;
852  default :
853  {
854  int success;
855  mixed err = catch { success = chatlog->log_room( room, true, msg ); };
856  object file = chatlog->get_logfile( room );
857  string filename = "";
858  if ( objectp(file) ) filename = sprintf( " to %s", get_module("filepath:tree")->object_to_filename(file) );
859  string result_msg = sprintf("Logging chat in room %s to file %s\r\n",
860  room->query_attribute(OBJ_NAME), filename );
861  if ( err ) result_msg = err[0];
862  else if ( !success ) result_msg = sprintf("Failed to turn on logging for room %s", room->query_attribute(OBJ_NAME));
863  send_message( cryptic_irc_name(oUser) + " PRIVMSG " + channel +
864  " : " + result_msg + "\r\n");
865  }
866  break;
867  }
868 
869  break;
870  }
871  DEBUG_IRC("Command not understood !\n");
872  return;
873  }
874 
875 
876  object chann = str_to_channel(channel);
877  if ( objectp(chann) ) {
878  sChannel = channel;
879  if ( msg[0] == '=' || msg[0] == '^' ) {
880  string res = execute(msg);
881  exec_response(res);
882  return;
883  }
884  chann->message(msg);
885  return;
886  }
887  else {
888  object user = MODULE_USERS->lookup(channel);
889  if ( objectp(user) ) {
890  if ( user == (geteuid() || this_user()) ) {
891  string res = execute("="+msg);
892  exec_response(res);
893  return;
894  }
895  user->message(msg);
896  if ( !(user->get_status() & CLIENT_FEATURES_CHAT) ) {
897  user->mail(msg);
898  send_reply(RPL_AWAY,
899  ({ channel, ": The user is currently "+
900  "not connected to sTeam - message mailed"}));
901  }
902  }
903  return;
904  }
905  send_reply(ERR_NORECIPIENT, ({ ":No recipient given (PRIVMSG)" }));
906 }
907 
908 public:
909 
910 protected:
911  void names(string channel)
912 {
913  object chann = str_to_channel(channel);
914  if ( objectp(chann) )
915  list_users(chann);
916 }
917 
918 public:
919 
920 protected:
921  void inventory()
922 {
923  array inv = (geteuid() || this_user())->get_inventory();
924  send_reply(371, ({ ":You are carrying: " }) );
925  foreach(inv, object o) {
926  send_reply(371, ({ ": " + o->get_identifier() + "[" +
927  o->get_object_id() + "]" }));
928  }
929 }
930 
931 public:
932 
933 string describe_object(object obj)
934 {
935  return obj->get_identifier() + " ["+obj->get_object_id() + "]";
936 }
937 
938 protected:
939  void look()
940 {
941  object channel = (geteuid() || this_user())->get_environment();
942  send_message(cryptic_irc_name(geteuid() || this_user()) + " PRIVMSG " +
943  channel_name(channel) + " : Container in Area:\r\n");
944 
945  string str = " ";
946  foreach(channel->get_inventory_by_class(CLASS_CONTAINER), object obj) {
947  str += obj->get_identifier()+", ";
948  }
949  send_message(cryptic_irc_name(geteuid() || this_user()) + " PRIVMSG " +
950  channel_name(channel) + " : " +
951  str + "\r\n");
952  str = "";
953  send_message(cryptic_irc_name(geteuid() || this_user()) + " PRIVMSG " +
954  channel_name(channel) + " : Documents in Area:\r\n");
955  foreach(channel->get_inventory_by_class(CLASS_DOCUMENT), object doc) {
956  str += doc->get_identifier()+", ";
957  }
958  send_message(cryptic_irc_name(geteuid() || this_user()) + " PRIVMSG " +
959  channel_name(channel) + " : " +
960  str + "\r\n");
961 }
962 
963 public:
964 
965 protected:
966  void give(string ostr, string toto, string tostr)
967 {
968  object too = MODULE_USERS->lookup(tostr);
969  object obj = oUser->get_object_byname(ostr);
970  if ( !objectp(too) )
971  send_reply(ERR_NOSUCHNICK);
972  if ( objectp(obj) )
973  {
974  mixed err = catch {
975  obj->move(too);
976  };
977  if ( err == 0 )
978  send_reply(371, ({ ": " + ostr + " given to " + tostr }));
979  }
980 }
981 
982 public:
983 
984 protected:
985  void compile(string fname)
986 {
987  send_myself(cmd_compile(fname));
988 }
989 
990 public:
991 
992 protected:
993  void ping(string t)
994 {
995  send_message(":"+sServer+ " PONG " + sServer + "\r\n");
996 }
997 
998 public:
999 
1000 protected:
1001  void pong(string t)
1002 {
1003 }
1004 
1005 public:
1006 
1007 protected:
1008  void whois(string user)
1009 {
1010  object ouser = MODULE_USERS->lookup(user);
1011  if ( !objectp(ouser) ) {
1012  send_reply(ERR_NOSUCHNICK);
1013  }
1014  else {
1015  send_reply(RPL_WHOISUSER,
1016  ({ ouser->get_identifier(),
1017  ouser->get_identifier(),
1018  ouser->get_ip(CLIENT_FEATURES_CHAT),
1019  "*",
1020  ":"+ouser->query_attribute(USER_FULLNAME) }));
1021  send_reply(RPL_WHOISCHANNELS,
1022  ({ ouser->get_identifier(),
1023  ":"+channel_name(ouser->get_environment()) }) );
1024  array sockets = ouser->get_sockets();
1025  mapping socketClasses = ([ ]);
1026  foreach(sockets, object s) {
1027  socketClasses[s->get_socket_name()]++;
1028  }
1029  string socketStr = "";
1030  foreach(indices(socketClasses), string c) {
1031  socketStr += c+"("+socketClasses[c]+"), ";
1032  }
1033  send_reply(RPL_WHOISCHANNELS,
1034  ({ ouser->get_identifier(), ":"+socketStr }));
1035  if ( !(ouser->get_status() & CLIENT_FEATURES_CHAT) )
1036  send_reply(RPL_AWAY, ({ ouser->get_identifier(),
1037  ":No chat client" }));
1038  send_reply(RPL_ENDOFWHOIS);
1039  }
1040 }
1041 
1042 public:
1043 
1044 protected:
1045  void dcc_send(object id)
1046 {
1047  Stdio.File sock = id->dcc_port->accept();
1048  object doc = id->doc;
1049  function f = doc->get_content_callback();
1050  sock->set_buffer(200000);
1051  string data;
1052  while ( (stringp(data = f())) ) {
1053  sock->write(data);
1054  sock->read(4);
1055  }
1056  sock->close();
1057  master()->dispose_port(id->port_nr);
1058  destruct(id->dcc_port);
1059  destruct(id);
1060 }
1061 
1062 public:
1063 
1064 protected:
1065  void download(string fname)
1066 {
1067  object doc = oChannel->get_object_byname(fname);
1068  int port = 33333;
1069  string ipaddr = _Server->get_server_ip();
1070 
1071  if ( stringp(ipaddr) && objectp(doc) ) {
1072  object id_dcc = Dcc();
1073  for ( ; port < 34000; port++ )
1074  if ( master()->free_port(port) )
1075  break;
1076  id_dcc->doc = doc;
1077  id_dcc->dcc_port = Stdio.Port();
1078  id_dcc->port_nr = port;
1079  id_dcc->dcc_port->set_id(id_dcc);
1080  id_dcc->dcc_port->bind(id_dcc->port_nr, dcc_send);
1081  master()->use_port(port);
1082  int ip, one, two, three, four;
1083 
1084  sscanf(ipaddr, "%d.%d.%d.%d", one, two, three, four);
1085  ip = (one<<24)+(two<<16)+(three<<8)+four;
1086  send_message(":sTeam!~steam@"+sServer+
1087  " PRIVMSG "+oUser->get_identifier()+
1088  " :\1DCC SEND "+fname+" "+
1089  ip + " " + id_dcc->port_nr + " " +
1090  doc->get_content_size()+"\1\r\n");
1091  }
1092 }
1093 
1094 public:
1095 
1096 protected:
1097  void users(string|void server)
1098 {
1099  array users = _STEAMUSER->get_members();
1100 
1101  send_reply(RPL_USERSSTART);
1102  foreach(users, object u) {
1103  if ( u->get_status() & CLIENT_FEATURES_CHAT ) {
1104  send_reply(RPL_USERS, ({ sprintf(":%-8s %-9s %-8s",
1105  u->get_identifier(), "IRC", "*" )}));
1106  }
1107  }
1108  send_reply(RPL_ENDOFUSERS);
1109 }
1110 
1111 public:
1112 
1113 protected:
1114  void quit(string message)
1115 {
1116  if ( objectp(oUser) ) oUser->disconnect();
1117  if ( objectp(roomListener) )
1118  destruct(roomListener);
1119  if ( objectp(logoutListener) )
1120  destruct(logoutListener);
1121  if ( objectp(tellListener) )
1122  destruct(tellListener);
1123  close_connection();
1124 }
1125 
1126 public:
1127 
1128 object get_user()
1129 {
1130  return oUser;
1131 }
1132 
1133 protected:
1134  mapping mCmd = ([
1135  "user": user,
1136  "pass": pass,
1137  "nick": nick,
1138  "list": list,
1139  "join": join,
1140  "mode": mode,
1141  "part": part,
1142  "leave": part,
1143  "privmsg": privmsg,
1144  "names": names,
1145  "users": users,
1146  "who": who,
1147  "whois": whois,
1148  "quit": quit,
1149  "ping": ping,
1150  "pong": pong,
1151  "ison": ison,
1152  "topic": topic,
1153  "invite": invite,
1154  "x": exec,
1155  "give": give,
1156  "compile": compile,
1157  "inv": inventory,
1158  "download": download,
1159  "look": look,
1160  ]);
1161 
1162 protected:
1163  void process_command(string cmd)
1164 {
1165  array commands;
1166  string prefix, trailing = 0;
1167 
1168  if ( sscanf(cmd, ":%s %s", prefix, cmd) > 0 ) {
1169  LOG("Prefix: "+ prefix);
1170  }
1171  if ( sscanf(cmd, "%s :%s", cmd, trailing ) == 2 ) {
1172  LOG("Trailing: "+ trailing);
1173  }
1174 
1175  commands = cmd / " ";
1176  LOG("COMMANDS:"+sprintf("%O",commands));
1177  if ( stringp(trailing) )
1178  commands += ({ trailing });
1179 
1180  for ( int i = 0; i < sizeof(commands); i++ ) {
1181  mixed token = commands[i];
1182  int l = strlen(token);
1183  if ( sscanf(token, "%d", token) && strlen((string)token) == l )
1184  commands[i] = token;
1185  }
1186  string fcmd = lower_case(commands[0]);
1187  function f = mCmd[fcmd];
1188  if ( functionp(f) ) {
1189  if ( objectp(oUser) ) {
1190  if ( fcmd != "ping" && fcmd != "pong" )
1191  oUser->command_done(time());
1192  }
1193  if ( sizeof(commands) == 1 )
1194  f();
1195  else
1196  f(@commands[1..]);
1197  return;
1198  }
1199  send_reply(ERR_UNKNOWNCOMMAND, ({ cmd, ":Unknown command" }));
1200 }
1201 
1202 public:
1203 
1204 int get_client_features() { return CLIENT_FEATURES_ALL; }
1205 string get_socket_name() { return "irc"; }
1206 string get_nick() { return sNick; }
1207 string describe() { return "IRC("+sNick+","+get_ip()+")"; }
1208 
1209 
1210 
1211 
1212 
1213 
1214 };