The InspIRCd Project
Home | Developers | Wiki | Forums | Bug Tracker | SVN | Download
Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members

m_services_account.cpp

Go to the documentation of this file.
00001 /*       +------------------------------------+
00002  *       | Inspire Internet Relay Chat Daemon |
00003  *       +------------------------------------+
00004  *
00005  *  InspIRCd: (C) 2002-2008 InspIRCd Development Team
00006  * See: http://www.inspircd.org/wiki/index.php/Credits
00007  *
00008  * This program is free but copyrighted software; see
00009  *            the file COPYING for details.
00010  *
00011  * ---------------------------------------------------
00012  */
00013 
00014 #include "inspircd.h"
00015 #include "account.h"
00016 
00017 /* $ModDesc: Povides support for ircu-style services accounts, including chmode +R, etc. */
00018 
00021 class AChannel_R : public SimpleChannelModeHandler
00022 {
00023  public:
00024         AChannel_R(InspIRCd* Instance) : SimpleChannelModeHandler(Instance, 'R') { }
00025 };
00026 
00029 class AUser_R : public SimpleUserModeHandler
00030 {
00031  public:
00032         AUser_R(InspIRCd* Instance) : SimpleUserModeHandler(Instance, 'R') { }
00033 };
00034 
00037 class AChannel_M : public SimpleChannelModeHandler
00038 {
00039  public:
00040         AChannel_M(InspIRCd* Instance) : SimpleChannelModeHandler(Instance, 'M') { }
00041 };
00042 
00043 class ModuleServicesAccount : public Module
00044 {
00045 
00046         AChannel_R* m1;
00047         AChannel_M* m2;
00048         AUser_R* m3;
00049  public:
00050         ModuleServicesAccount(InspIRCd* Me) : Module(Me)
00051         {
00052 
00053                 m1 = new AChannel_R(ServerInstance);
00054                 m2 = new AChannel_M(ServerInstance);
00055                 m3 = new AUser_R(ServerInstance);
00056                 if (!ServerInstance->Modes->AddMode(m1) || !ServerInstance->Modes->AddMode(m2) || !ServerInstance->Modes->AddMode(m3))
00057                         throw ModuleException("You cannot load m_services.so and m_services_account.so at the same time (or some other module has claimed our modes)!");
00058 
00059                 Implementation eventlist[] = { I_OnWhois, I_OnUserPreMessage, I_OnUserPreNotice, I_OnUserPreJoin,
00060                         I_OnSyncUserMetaData, I_OnUserQuit, I_OnCleanup, I_OnDecodeMetaData, I_On005Numeric };
00061 
00062                 ServerInstance->Modules->Attach(eventlist, this, 9);
00063         }
00064 
00065         virtual void On005Numeric(std::string &t)
00066         {
00067                 ServerInstance->AddExtBanChar('R');
00068                 ServerInstance->AddExtBanChar('M');
00069         }
00070 
00071         /* <- :twisted.oscnet.org 330 w00t2 w00t2 w00t :is logged in as */
00072         virtual void OnWhois(User* source, User* dest)
00073         {
00074                 std::string *account;
00075                 dest->GetExt("accountname", account);
00076 
00077                 if (account)
00078                 {
00079                         ServerInstance->SendWhoisLine(source, dest, 330, "%s %s %s :is logged in as", source->nick.c_str(), dest->nick.c_str(), account->c_str());
00080                 }
00081         }
00082 
00083 
00084         virtual int OnUserPreMessage(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
00085         {
00086                 std::string *account;
00087 
00088                 if (!IS_LOCAL(user))
00089                         return 0;
00090 
00091                 user->GetExt("accountname", account);
00092 
00093                 if ((ServerInstance->ULine(user->nick.c_str())) || (ServerInstance->ULine(user->server)))
00094                 {
00095                         // user is ulined, can speak regardless
00096                         return 0;
00097                 }
00098 
00099                 if (target_type == TYPE_CHANNEL)
00100                 {
00101                         Channel* c = (Channel*)dest;
00102 
00103                         if ((c->IsModeSet('M')) && (!account))
00104                         {
00105                                 // user messaging a +M channel and is not registered
00106                                 user->WriteNumeric(477, ""+std::string(user->nick)+" "+std::string(c->name)+" :You need to be identified to a registered account to message this channel");
00107                                 return 1;
00108                         }
00109 
00110                         if (account)
00111                         {
00112                                 if (c->IsExtBanned(*account, 'M'))
00113                                 {
00114                                         // may not speak
00115                                         user->WriteNumeric(477, ""+std::string(user->nick)+" "+std::string(c->name)+" :You may not speak in this channel");
00116                                         return 1;
00117                                 }
00118                         }
00119                 }
00120 
00121                 if (target_type == TYPE_USER)
00122                 {
00123                         User* u = (User*)dest;
00124 
00125                         if ((u->modes['R'-65]) && (!account))
00126                         {
00127                                 // user messaging a +R user and is not registered
00128                                 user->WriteNumeric(477, ""+ user->nick +" "+ u->nick +" :You need to be identified to a registered account to message this user");
00129                                 return 1;
00130                         }
00131                 }
00132                 return 0;
00133         }
00134 
00135         virtual int OnUserPreNotice(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
00136         {
00137                 return OnUserPreMessage(user, dest, target_type, text, status, exempt_list);
00138         }
00139 
00140         virtual int OnUserPreJoin(User* user, Channel* chan, const char* cname, std::string &privs, const std::string &keygiven)
00141         {
00142                 std::string *account;
00143                 user->GetExt("accountname", account);
00144 
00145                 if (chan)
00146                 {
00147                         if (chan->IsModeSet('R'))
00148                         {
00149                                 if (!account)
00150                                 {
00151                                         if ((ServerInstance->ULine(user->nick.c_str())) || (ServerInstance->ULine(user->server)))
00152                                         {
00153                                                 // user is ulined, won't be stopped from joining
00154                                                 return 0;
00155                                         }
00156                                         // joining a +R channel and not identified
00157                                         user->WriteNumeric(477, user->nick + " " + chan->name + " :You need to be identified to a registered account to join this channel");
00158                                         return 1;
00159                                 }
00160                         }
00161 
00162                         if (account)
00163                         {
00164                                 if (chan->IsExtBanned(*account, 'R'))
00165                                 {
00166                                         // may not join
00167                                         user->WriteNumeric(ERR_BANNEDFROMCHAN, "%s %s :Cannot join channel (You're banned)", user->nick.c_str(),  chan->name.c_str());
00168                                         return 1;
00169                                 }
00170                         }
00171                 }
00172                 return 0;
00173         }
00174 
00175         // Whenever the linking module wants to send out data, but doesnt know what the data
00176         // represents (e.g. it is metadata, added to a User or Channel by a module) then
00177         // this method is called. We should use the ProtoSendMetaData function after we've
00178         // corrected decided how the data should look, to send the metadata on its way if
00179         // it is ours.
00180         virtual void OnSyncUserMetaData(User* user, Module* proto, void* opaque, const std::string &extname, bool displayable)
00181         {
00182                 // check if the linking module wants to know about OUR metadata
00183                 if (extname == "accountname")
00184                 {
00185                         // check if this user has an swhois field to send
00186                         std::string* account;
00187                         user->GetExt("accountname", account);
00188                         if (account)
00189                         {
00190                                 // remove any accidental leading/trailing spaces
00191                                 trim(*account);
00192 
00193                                 // call this function in the linking module, let it format the data how it
00194                                 // sees fit, and send it on its way. We dont need or want to know how.
00195                                 proto->ProtoSendMetaData(opaque,TYPE_USER,user,extname,*account);
00196                         }
00197                 }
00198         }
00199 
00200         // when a user quits, tidy up their metadata
00201         virtual void OnUserQuit(User* user, const std::string &message, const std::string &oper_message)
00202         {
00203                 std::string* account;
00204                 user->GetExt("accountname", account);
00205                 if (account)
00206                 {
00207                         user->Shrink("accountname");
00208                         delete account;
00209                 }
00210         }
00211 
00212         // if the module is unloaded, tidy up all our dangling metadata
00213         virtual void OnCleanup(int target_type, void* item)
00214         {
00215                 if (target_type == TYPE_USER)
00216                 {
00217                         User* user = (User*)item;
00218                         std::string* account;
00219                         user->GetExt("accountname", account);
00220                         if (account)
00221                         {
00222                                 user->Shrink("accountname");
00223                                 delete account;
00224                         }
00225                 }
00226         }
00227 
00228         // Whenever the linking module receives metadata from another server and doesnt know what
00229         // to do with it (of course, hence the 'meta') it calls this method, and it is up to each
00230         // module in turn to figure out if this metadata key belongs to them, and what they want
00231         // to do with it.
00232         // In our case we're only sending a single string around, so we just construct a std::string.
00233         // Some modules will probably get much more complex and format more detailed structs and classes
00234         // in a textual way for sending over the link.
00235         virtual void OnDecodeMetaData(int target_type, void* target, const std::string &extname, const std::string &extdata)
00236         {
00237                 // check if its our metadata key, and its associated with a user
00238                 if ((target_type == TYPE_USER) && (extname == "accountname"))
00239                 {
00240                         User* dest = (User*)target;
00241 
00242                         /* logging them out? */
00243                         if (extdata.empty())
00244                         {
00245                                 std::string* account;
00246                                 dest->GetExt("accountname", account);
00247                                 if (account)
00248                                 {
00249                                         dest->Shrink("accountname");
00250                                         delete account;
00251                                 }
00252                         }
00253                         else
00254                         {
00255                                 // if they dont already have an accountname field, accept the remote server's
00256                                 std::string* text;
00257                                 if (!dest->GetExt("accountname", text))
00258                                 {
00259                                         text = new std::string(extdata);
00260                                         // remove any accidental leading/trailing spaces
00261                                         trim(*text);
00262                                         dest->Extend("accountname", text);
00263 
00264                                         if (IS_LOCAL(dest))
00265                                                 dest->WriteNumeric(900, "%s %s %s :You are now logged in as %s", dest->nick.c_str(), dest->GetFullHost().c_str(), text->c_str(), text->c_str());
00266 
00267                                         AccountData ac;
00268                                         ac.user = dest;
00269                                         ac.account = *text;
00270                                         Event n((char*)&ac, this, "account_login");
00271                                         n.Send(ServerInstance);
00272                                 }
00273                         }
00274                 }
00275         }
00276 
00277         virtual ~ModuleServicesAccount()
00278         {
00279                 ServerInstance->Modes->DelMode(m1);
00280                 ServerInstance->Modes->DelMode(m2);
00281                 ServerInstance->Modes->DelMode(m3);
00282                 delete m1;
00283                 delete m2;
00284                 delete m3;
00285         }
00286 
00287         virtual Version GetVersion()
00288         {
00289                 return Version("$Id: m_services_account.cpp 10379 2008-09-02 20:09:01Z brain $",VF_COMMON|VF_VENDOR,API_VERSION);
00290         }
00291 };
00292 
00293 MODULE_INIT(ModuleServicesAccount)