1 /* Copyright (C) 2000-2005 Thomas Bopp, Thorsten Hampel, Ludger Merkens
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.
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.
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
17 * $Id: irc.pike,v 1.3 2010/01/27 12:05:35 astra Exp $
19 inherit "/net/coal/login";
20 inherit "/net/base/line";
21 inherit "/net/base/cmd";
22 inherit Events.Listener;
30 #include <attributes.h>
31 class irc : public login,line,cmd{
38 #define STATE_AUTHORIZATION 1
39 #define STATE_TRANSACTION 2
40 #define STATE_UPDATE 3
46 #define DEBUG_IRC(s, args...) werror("IRC: " + s+"\n", args)
48 #define DEBUG_IRC(s, args...)
53 string sServer = _Server->get_server_name();
73 void create(int events, object obj) {
74 ::create(events, PHASE_NOTIFY, obj, 0, oUser);
75 obj->listen_event(this_object());
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);
82 function get_callback() {
86 mapping save() { return 0; }
89 return "IrcListener()";
93 IrcListener roomListener;
94 IrcListener logoutListener;
95 IrcListener tellListener;
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
106 #define RPL_LISTSTART 321
108 #define RPL_LISTEND 323
109 #define RPL_WHOREPLY 352
110 #define RPL_NAMEREPLY 353
111 #define RPL_ENDOFNAMES 366
113 #define RPL_MOTDSTART 375
115 #define RPL_ENDOFMOTD 376
117 #define RPL_USERSSTART 392
118 #define RPL_USERS 393
119 #define RPL_ENDOFUSERS 394
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
131 #define ERR_NICKCOLLISION 436
132 #define ERR_NOTONCHANNEL 442
134 #define ERR_NEEDMOREPARAMS 461
135 #define ERR_PASSWDMISSMATCH 464
136 #define ERR_UNKNOWNMODE 472
137 #define ERR_INVITEONLYCHAN 473
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",
154 void send_reply(string|int cmd, string|void|array params)
158 if ( arrayp(params) ) {
159 params = params * " ";
161 else if ( !stringp(params) )
164 LOG("Sending ok ("+cmd+")");
166 if ( stringp(mReplies[cmd]) )
167 trailing = mReplies[cmd];
170 else if ( cmd < 100 )
173 cmd = ":"+sServer+" "+ cmd + " " +
174 (objectp(oUser) ? " " + oUser->get_identifier() : "");
175 if ( stringp(trailing) ) {
176 params += ":"+trailing;
179 if ( stringp(params) )
180 send_message(cmd + " " + params + "\r\n");
182 send_message(cmd + "\r\n");
188 void send_myself(string msg)
190 send_message(cryptic_irc_name(oUser) + " PRIVMSG SERVER :" +msg+ "\r\n");
197 string addr = query_address();
199 sscanf(addr, "%*s %d", port);
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")+","+
213 identsock->write(msg);
217 while ( (time()-t) < I_TIMEOUT && (
218 !stringp(str=identsock->read()) || strlen(str) == 0) )
222 send_message(":"+sServer+
223 " NOTICE AUTH : *** Found your hostname\r\n");
231 if ( catch(send_message("PING " + sServer + "\r\n")) )
232 return; // end thread when connection is down
236 void create(object f)
239 send_message(":"+sServer+
240 " NOTICE AUTH : *** Looking up your hostname...\r\n");
241 send_message(":"+sServer+" NOTICE AUTH : *** Checking Ident\r\n");
243 //thread_create(identd);
244 thread_create(pinging);
246 sClientClass = "irc";
251 string cryptic_irc_name(object obj)
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();
263 if ( !(obj->get_object_class() & CLASS_USER) )
264 return ":("+obj->get_identifier()+")!~"+obj->get_identifier() +"@"+sServer;
267 return ":"+obj->get_identifier() + "!~"+obj->get_identifier()+"@"+
268 obj->get_ip(CLIENT_FEATURES_CHAT);
271 string channel_name(object obj)
275 if ( objectp(obj) ) {
276 channel = _FILEPATH->object_to_filename(obj);
277 if ( sscanf(channel, "/home/%s", channel) > 0 )
278 channel = "&" + replace(channel," ", "^");
280 channel = "#" + channel;
286 void notify_irc(int event, mixed ... args)
288 object user = geteuid() || this_user();
289 if ( !objectp(oUser) || !objectp(user) )
295 send_message(cryptic_irc_name(user) + " PRIVMSG " +
296 channel_name(args[0]) + " :" + args[2] +"\r\n");
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");
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");
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");
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");
323 send_message(cryptic_irc_name(user) + " PRIVMSG "+
324 args[0]->get_identifier() + " :"+args[2] + "\r\n");
329 object str_to_channel(string channel)
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..],"^"," "));
338 return _FILEPATH->path_to_object(channel[1..]);
341 /*************************************************************************
342 * authorization, login stuff
349 if ( oUser == _GUEST )
351 if ( stringp(sNick) )
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");
379 void connect_user(object u)
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);
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");
414 user = get_module("auth")->authenticate(sNick, sPass);
417 if ( objectp(oUser) ) {
426 send_reply(ERR_PASSWDMISSMATCH, sPass);
428 /* ERR_NICKNAMEINUSE ??? */
436 void list(void|string param)
438 LOG("list(" + param+")");
440 array groups = MODULE_GROUPS->get_groups();
441 foreach(groups, object g) {
442 object r = g->query_attribute(GROUP_WORKROOM);
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");
454 send_reply(RPL_LISTEND, ":End of /LIST");
462 int join_channel(object channel)
465 oUser->move(channel);
466 if ( objectp(roomListener) )
467 destruct(roomListener);
468 if ( objectp(logoutListener) )
469 destruct(logoutListener);
471 roomListener = IrcListener(EVENT_SAY|EVENT_ENTER_INVENTORY|
472 EVENT_LEAVE_INVENTORY, channel);
473 logoutListener= IrcListener(EVENT_LOGIN|EVENT_LOGOUT|EVENTS_MONITORED,
482 void list_users(object channel)
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() + " ";
490 send_reply(RPL_NAMEREPLY, " = " + channel_name(channel)+" :" +
492 send_reply(RPL_ENDOFNAMES, ":End of /NAMES list.");
498 array get_users(object channel)
501 object event = channel->get_event(EVENT_SAY);
502 array listeners = event->get_listeners();
503 foreach(listeners, object l) {
506 object u = l->get_listening();
507 if ( objectp(u) && u->get_status() & CLIENT_FEATURES_CHAT )
516 void who(string channel)
520 object chann = str_to_channel(channel);
522 if ( objectp(chann) ) {
523 users = get_users(chann);
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(),
534 ": 0 "+user->query_attribute(USER_FULLNAME) }));
536 send_reply(RPL_WHOREPLY,
537 ({ channel_name(chann),
539 _Server->get_server_name(),
540 _Server->get_server_name(),
543 ": 0 sTeam Server" }));
544 send_reply(RPL_ENDOFWHO);
551 void join(string channels)
556 sscanf(channels, "%s %s", channels, keys);
557 channs = channels / ",";
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");
565 if ( objectp(chann) ) {
566 if ( join_channel(chann) ) {
568 string msg = cryptic_irc_name(oUser)+" JOIN "+
569 channel_name(chann)+"\r\n";
575 DEBUG_IRC("Invite Only Channel Message returned ...");
576 send_reply(ERR_INVITEONLYCHAN, channs[0]);
580 DEBUG_IRC("No such channel returned upon joining %s", channels);
581 send_reply(ERR_NOSUCHCHANNEL, channs[0]);
588 void part(string channel)
590 object chann = str_to_channel(channel);
591 if ( objectp(chann) ) {
592 if ( chann == oChannel ) {
594 send_message(cryptic_irc_name(oUser)+" PART "+
595 channel_name(chann)+"\r\n");
598 send_reply(ERR_NOTONCHANNEL, channel);
601 send_reply(ERR_NOSUCHCHANNEL, channel);
606 void send_invite(string channel)
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");
613 void invite(string user, string channel)
615 object chann = str_to_channel(channel);
616 if ( objectp(chann) ) {
617 // give the user permissions
618 object u = MODULE_USERS->lookup(user);
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);
629 send_reply(ERR_NOSUCHNICK);
631 send_reply(ERR_NOSUCHCHANNEL, channel);
637 void ison(string userlist)
639 array rpl_user_list = ({ });
640 array ul = userlist / " ";
641 foreach(ul, string user) {
642 object u = MODULE_USERS->lookup(user);
644 if (u->get_client_features() & CLIENT_FEATURES_CHAT) {
645 rpl_user_list += ({ user });
649 if (sizeof(rpl_user_list) > 0) {
650 rpl_user_list[0] = ":" + rpl_user_list[0];
652 send_reply(RPL_ISON, rpl_user_list);
658 void mode(string channel, void|string m)
661 if ( !stringp(m) || strlen(m) == 0 )
664 send_reply(ERR_UNKNOWNMODE);
670 void reply_topic(object channel)
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 }));
683 void topic(string channel, string topic)
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);
698 void exec_response(string res)
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");
713 void exec(string msg)
715 string res = execute("^" + msg);
722 void establish_dcc(string ip, int port, string fname, int size)
724 object conn = Stdio.File();
725 DEBUG_IRC("establishing dcc to "+ip+"\n");
726 conn->connect(ip, port);
727 conn->set_buffer(200000);
731 while ( stringp(rd=conn->read(1024,1)) && strlen(rd) > 0 ) {
732 DEBUG_IRC("Read "+ strlen(rd) + " bytes...\n");
734 int sz = strlen(data);
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 ));
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, ]) );
749 doc->set_content(data);
755 void privmsg(string channel, string msg)
757 LOG("privmsg("+channel+","+msg+")");
759 if ( lower_case(channel) == "steam" ) {
762 if ( sscanf(msg, "\1%s %s\1", cmd, msg) != 2 &&
763 sscanf(msg, "%s %s", cmd, msg) != 2 )
765 DEBUG_IRC("Command is "+ cmd+"\n");
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");
778 object u = get_module("auth")->authenticate(sNick, sPass);
780 send_message(cryptic_irc_name(oUser) + " PRIVMSG NICKSERV :"+
781 "User not found or wrong password !\r\n");
788 array args = (msg / " ");
789 DEBUG_IRC("DCC="+sprintf("%O",args)+"\n");
790 if ( sizeof(args) > 4 )
792 if ( args[0] == "SEND" ) {
793 establish_dcc(get_ip(), (int)args[3], args[1], sz);
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" );
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");
816 send_message( cryptic_irc_name(oUser) + " PRIVMSG " + channel +
817 sprintf(" : Active chat-Logs: %O\r\n", chatlog->get_rooms()) );
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");
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");
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");
871 DEBUG_IRC("Command not understood !\n");
876 object chann = str_to_channel(channel);
877 if ( objectp(chann) ) {
879 if ( msg[0] == '=' || msg[0] == '^' ) {
880 string res = execute(msg);
888 object user = MODULE_USERS->lookup(channel);
889 if ( objectp(user) ) {
890 if ( user == (geteuid() || this_user()) ) {
891 string res = execute("="+msg);
896 if ( !(user->get_status() & CLIENT_FEATURES_CHAT) ) {
899 ({ channel, ": The user is currently "+
900 "not connected to sTeam - message mailed"}));
905 send_reply(ERR_NORECIPIENT, ({ ":No recipient given (PRIVMSG)" }));
911 void names(string channel)
913 object chann = str_to_channel(channel);
914 if ( objectp(chann) )
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() + "]" }));
933 string describe_object(object obj)
935 return obj->get_identifier() + " ["+obj->get_object_id() + "]";
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");
946 foreach(channel->get_inventory_by_class(CLASS_CONTAINER), object obj) {
947 str += obj->get_identifier()+", ";
949 send_message(cryptic_irc_name(geteuid() || this_user()) + " PRIVMSG " +
950 channel_name(channel) + " : " +
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()+", ";
958 send_message(cryptic_irc_name(geteuid() || this_user()) + " PRIVMSG " +
959 channel_name(channel) + " : " +
966 void give(string ostr, string toto, string tostr)
968 object too = MODULE_USERS->lookup(tostr);
969 object obj = oUser->get_object_byname(ostr);
971 send_reply(ERR_NOSUCHNICK);
978 send_reply(371, ({ ": " + ostr + " given to " + tostr }));
985 void compile(string fname)
987 send_myself(cmd_compile(fname));
995 send_message(":"+sServer+ " PONG " + sServer + "\r\n");
1008 void whois(string user)
1010 object ouser = MODULE_USERS->lookup(user);
1011 if ( !objectp(ouser) ) {
1012 send_reply(ERR_NOSUCHNICK);
1015 send_reply(RPL_WHOISUSER,
1016 ({ ouser->get_identifier(),
1017 ouser->get_identifier(),
1018 ouser->get_ip(CLIENT_FEATURES_CHAT),
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()]++;
1029 string socketStr = "";
1030 foreach(indices(socketClasses), string c) {
1031 socketStr += c+"("+socketClasses[c]+"), ";
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);
1045 void dcc_send(object id)
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);
1052 while ( (stringp(data = f())) ) {
1057 master()->dispose_port(id->port_nr);
1058 destruct(id->dcc_port);
1065 void download(string fname)
1067 object doc = oChannel->get_object_byname(fname);
1069 string ipaddr = _Server->get_server_ip();
1071 if ( stringp(ipaddr) && objectp(doc) ) {
1072 object id_dcc = Dcc();
1073 for ( ; port < 34000; port++ )
1074 if ( master()->free_port(port) )
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;
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");
1097 void users(string|void server)
1099 array users = _STEAMUSER->get_members();
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", "*" )}));
1108 send_reply(RPL_ENDOFUSERS);
1114 void quit(string message)
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);
1158 "download": download,
1163 void process_command(string cmd)
1166 string prefix, trailing = 0;
1168 if ( sscanf(cmd, ":%s %s", prefix, cmd) > 0 ) {
1169 LOG("Prefix: "+ prefix);
1171 if ( sscanf(cmd, "%s :%s", cmd, trailing ) == 2 ) {
1172 LOG("Trailing: "+ trailing);
1175 commands = cmd / " ";
1176 LOG("COMMANDS:"+sprintf("%O",commands));
1177 if ( stringp(trailing) )
1178 commands += ({ trailing });
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;
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());
1193 if ( sizeof(commands) == 1 )
1199 send_reply(ERR_UNKNOWNCOMMAND, ({ cmd, ":Unknown command" }));
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()+")"; }