]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/coremods/core_reloadmodule.cpp
Fix various documentation comments.
[user/henk/code/inspircd.git] / src / coremods / core_reloadmodule.cpp
1 /*
2  * InspIRCd -- Internet Relay Chat Daemon
3  *
4  *   Copyright (C) 2017-2019, 2021 Sadie Powell <sadie@witchery.services>
5  *   Copyright (C) 2014-2016, 2018 Attila Molnar <attilamolnar@hush.com>
6  *   Copyright (C) 2012 Robby <robby@chatbelgie.be>
7  *   Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
8  *   Copyright (C) 2007, 2010 Craig Edwards <brain@inspircd.org>
9  *   Copyright (C) 2007 Dennis Friis <peavey@inspircd.org>
10  *
11  * This file is part of InspIRCd.  InspIRCd is free software: you can
12  * redistribute it and/or modify it under the terms of the GNU General Public
13  * License as published by the Free Software Foundation, version 2.
14  *
15  * This program is distributed in the hope that it will be useful, but WITHOUT
16  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
22  */
23
24
25 #include "inspircd.h"
26 #include "listmode.h"
27 #include "modules/reload.h"
28
29 static Events::ModuleEventProvider* reloadevprov;
30 static ClientProtocol::Serializer* dummyserializer;
31
32 class DummySerializer : public ClientProtocol::Serializer
33 {
34         bool Parse(LocalUser* user, const std::string& line, ClientProtocol::ParseOutput& parseoutput) CXX11_OVERRIDE
35         {
36                 return false;
37         }
38
39         ClientProtocol::SerializedMessage Serialize(const ClientProtocol::Message& msg, const ClientProtocol::TagSelection& tagwl) const CXX11_OVERRIDE
40         {
41                 return ClientProtocol::SerializedMessage();
42         }
43
44  public:
45         DummySerializer(Module* mod)
46                 : ClientProtocol::Serializer(mod, "dummy")
47         {
48         }
49 };
50
51 class CommandReloadmodule : public Command
52 {
53         Events::ModuleEventProvider evprov;
54         DummySerializer dummyser;
55
56  public:
57         /** Constructor for reloadmodule.
58          */
59         CommandReloadmodule(Module* parent)
60                 : Command(parent, "RELOADMODULE", 1)
61                 , evprov(parent, "event/reloadmodule")
62                 , dummyser(parent)
63         {
64                 reloadevprov = &evprov;
65                 dummyserializer = &dummyser;
66                 flags_needed = 'o';
67                 syntax = "<modulename>";
68         }
69
70         /** Handle command.
71          * @param parameters The parameters to the command
72          * @param user The user issuing the command
73          * @return A value from CmdResult to indicate command success or failure.
74          */
75         CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE;
76 };
77
78 namespace ReloadModule
79 {
80
81 class DataKeeper
82 {
83         /** Data we save for each mode and extension provided by the module
84          */
85         struct ProviderInfo
86         {
87                 std::string itemname;
88                 union
89                 {
90                         ModeHandler* mh;
91                         ExtensionItem* extitem;
92                         ClientProtocol::Serializer* serializer;
93                 };
94
95                 ProviderInfo(ModeHandler* mode)
96                         : itemname(mode->name)
97                         , mh(mode)
98                 {
99                 }
100
101                 ProviderInfo(ExtensionItem* ei)
102                         : itemname(ei->name)
103                         , extitem(ei)
104                 {
105                 }
106
107                 ProviderInfo(ClientProtocol::Serializer* ser)
108                         : itemname(ser->name)
109                         , serializer(ser)
110                 {
111                 }
112         };
113
114         struct InstanceData
115         {
116                 /** Position of the ModeHandler or ExtensionItem that the serialized data belongs to
117                  */
118                 size_t index;
119
120                 /** Serialized data
121                  */
122                 std::string serialized;
123
124                 InstanceData(size_t Index, const std::string& Serialized)
125                         : index(Index)
126                         , serialized(Serialized)
127                 {
128                 }
129         };
130
131         struct ModesExts
132         {
133                 /** Mode data for the object, one entry per mode set by the module being reloaded
134                  */
135                 std::vector<InstanceData> modelist;
136
137                 /** Extensions for the object, one entry per extension set by the module being reloaded
138                  */
139                 std::vector<InstanceData> extlist;
140
141                 bool empty() const { return ((modelist.empty()) && (extlist.empty())); }
142
143                 void swap(ModesExts& other)
144                 {
145                         modelist.swap(other.modelist);
146                         extlist.swap(other.extlist);
147                 }
148         };
149
150         struct OwnedModesExts : public ModesExts
151         {
152                 /** User uuid or channel name
153                  */
154                 std::string owner;
155
156                 OwnedModesExts(const std::string& Owner)
157                         : owner(Owner)
158                 {
159                 }
160         };
161
162         // Data saved for each channel
163         struct ChanData : public OwnedModesExts
164         {
165                 /** Type of data stored for each member who has any affected modes or extensions set
166                  */
167                 typedef OwnedModesExts MemberData;
168
169                 /** List of data (modes and extensions) about each member
170                  */
171                 std::vector<MemberData> memberdatalist;
172
173                 ChanData(Channel* chan)
174                         : OwnedModesExts(chan->name)
175                 {
176                 }
177         };
178
179         // Data saved for each user
180         struct UserData : public OwnedModesExts
181         {
182                 static const size_t UNUSED_INDEX = (size_t)-1;
183                 size_t serializerindex;
184
185                 UserData(User* user, size_t serializeridx)
186                         : OwnedModesExts(user->uuid)
187                         , serializerindex(serializeridx)
188                 {
189                 }
190         };
191
192         /** Module being reloaded
193          */
194         Module* mod;
195
196         /** Stores all user and channel modes provided by the module
197          */
198         std::vector<ProviderInfo> handledmodes[2];
199
200         /** Stores all extensions provided by the module
201          */
202         std::vector<ProviderInfo> handledexts;
203
204         /** Stores all serializers provided by the module
205          */
206         std::vector<ProviderInfo> handledserializers;
207
208         /** Stores all of the module data related to users
209          */
210         std::vector<UserData> userdatalist;
211
212         /** Stores all of the module data related to channels and memberships
213          */
214         std::vector<ChanData> chandatalist;
215
216         /** Data attached by modules
217          */
218         ReloadModule::CustomData moddata;
219
220         void SaveExtensions(Extensible* extensible, std::vector<InstanceData>& extdatalist);
221         void SaveMemberData(Channel* chan, std::vector<ChanData::MemberData>& memberdatalist);
222         static void SaveListModes(Channel* chan, ListModeBase* lm, size_t index, ModesExts& currdata);
223         size_t SaveSerializer(User* user);
224
225         /** Get the index of a ProviderInfo representing the serializer in the handledserializers list.
226          * If the serializer is not already in the list it is added.
227          * @param serializer Serializer to get an index to.
228          * @return Index of the ProviderInfo representing the serializer.
229          */
230         size_t GetSerializerIndex(ClientProtocol::Serializer* serializer);
231
232         void CreateModeList(ModeType modetype);
233         void DoSaveUsers();
234         void DoSaveChans();
235
236         /** Link previously saved extension names to currently available ExtensionItems
237          */
238         void LinkExtensions();
239
240         /** Link previously saved mode names to currently available ModeHandlers
241          * @param modetype Type of the modes to look for
242          */
243         void LinkModes(ModeType modetype);
244
245         /** Link previously saved serializer names to currently available Serializers
246          */
247         void LinkSerializers();
248
249         void DoRestoreUsers();
250         void DoRestoreChans();
251         void DoRestoreModules();
252
253         /** Restore previously saved modes and extensions on an Extensible.
254          * The extensions are set directly on the extensible, the modes are added into the provided mode change list.
255          * @param data Data to unserialize from
256          * @param extensible Object to restore
257          * @param modetype MODETYPE_USER if the object being restored is a User, MODETYPE_CHANNEL otherwise
258          * (for Channels and Memberships).
259          * @param modechange Mode change to populate with the modes
260          */
261         void RestoreObj(const OwnedModesExts& data, Extensible* extensible, ModeType modetype, Modes::ChangeList& modechange);
262
263         /** Restore all previously saved extensions on an Extensible
264          * @param list List of extensions and their serialized data to restore
265          * @param extensible Target Extensible
266          */
267         void RestoreExtensions(const std::vector<InstanceData>& list, Extensible* extensible);
268
269         /** Restore all previously saved modes on a User, Channel or Membership
270          * @param list List of modes to restore
271          * @param modetype MODETYPE_USER if the object being restored is a User, MODETYPE_CHANNEL otherwise
272          * @param modechange Mode change to populate with the modes
273          */
274         void RestoreModes(const std::vector<InstanceData>& list, ModeType modetype, Modes::ChangeList& modechange);
275
276         /** Restore previously saved serializer on a User.
277          * Quit the user if the serializer cannot be restored.
278          * @param serializerindex Saved serializer index to restore.
279          * @param user User whose serializer to restore. If not local then calling this method is a no-op.
280          * @return True if the serializer didn't need restoring or was restored successfully.
281          * False if the serializer should have been restored but the required serializer is unavailable and the user was quit.
282          */
283         bool RestoreSerializer(size_t serializerindex, User* user);
284
285         /** Restore all modes and extensions of all members on a channel
286          * @param chan Channel whose members are being restored
287          * @param memberdatalist Data to restore
288          * @param modechange Mode change to populate with prefix modes
289          */
290         void RestoreMemberData(Channel* chan, const std::vector<ChanData::MemberData>& memberdatalist, Modes::ChangeList& modechange);
291
292         /** Verify that a service which had its data saved is available and owned by the module that owned it previously
293          * @param service Service descriptor
294          * @param type Human-readable type of the service for log messages
295          */
296         void VerifyServiceProvider(const ProviderInfo& service, const char* type);
297
298  public:
299         /** Save module state
300          * @param currmod Module whose data to save
301          */
302         void Save(Module* currmod);
303
304         /** Restore module state
305          * @param newmod Newly loaded instance of the module which had its data saved
306          */
307         void Restore(Module* newmod);
308
309         /** Handle reload failure
310          */
311         void Fail();
312 };
313
314 void DataKeeper::DoSaveUsers()
315 {
316         ModesExts currdata;
317
318         const user_hash& users = ServerInstance->Users->GetUsers();
319         for (user_hash::const_iterator i = users.begin(); i != users.end(); ++i)
320         {
321                 User* const user = i->second;
322
323                 // Serialize user modes
324                 for (size_t j = 0; j < handledmodes[MODETYPE_USER].size(); j++)
325                 {
326                         ModeHandler* mh = handledmodes[MODETYPE_USER][j].mh;
327                         if (user->IsModeSet(mh))
328                                 currdata.modelist.push_back(InstanceData(j, mh->GetUserParameter(user)));
329                 }
330
331                 // Serialize all extensions attached to the User
332                 SaveExtensions(user, currdata.extlist);
333
334                 // Save serializer name if applicable and get an index to it
335                 size_t serializerindex = SaveSerializer(user);
336
337                 // Add to list if the user has any modes or extensions set that we are interested in, otherwise we don't
338                 // have to do anything with this user when restoring
339                 if ((!currdata.empty()) || (serializerindex != UserData::UNUSED_INDEX))
340                 {
341                         userdatalist.push_back(UserData(user, serializerindex));
342                         userdatalist.back().swap(currdata);
343                 }
344         }
345 }
346
347 size_t DataKeeper::GetSerializerIndex(ClientProtocol::Serializer* serializer)
348 {
349         for (size_t i = 0; i < handledserializers.size(); i++)
350         {
351                 if (handledserializers[i].serializer == serializer)
352                         return i;
353         }
354
355         handledserializers.push_back(ProviderInfo(serializer));
356         return handledserializers.size()-1;
357 }
358
359 size_t DataKeeper::SaveSerializer(User* user)
360 {
361         LocalUser* const localuser = IS_LOCAL(user);
362         if ((!localuser) || (!localuser->serializer))
363                 return UserData::UNUSED_INDEX;
364         if (localuser->serializer->creator != mod)
365                 return UserData::UNUSED_INDEX;
366
367         const size_t serializerindex = GetSerializerIndex(localuser->serializer);
368         localuser->serializer = dummyserializer;
369         return serializerindex;
370 }
371
372 void DataKeeper::SaveExtensions(Extensible* extensible, std::vector<InstanceData>& extdata)
373 {
374         const Extensible::ExtensibleStore& setexts = extensible->GetExtList();
375
376         // Position of the extension saved in the handledexts list
377         size_t index = 0;
378         for (std::vector<ProviderInfo>::const_iterator i = handledexts.begin(); i != handledexts.end(); ++i, index++)
379         {
380                 ExtensionItem* const item = i->extitem;
381                 Extensible::ExtensibleStore::const_iterator it = setexts.find(item);
382                 if (it == setexts.end())
383                         continue;
384
385                 std::string value = item->ToInternal(extensible, it->second);
386                 // If the serialized value is empty the extension won't be saved and restored
387                 if (!value.empty())
388                         extdata.push_back(InstanceData(index, value));
389         }
390 }
391
392 void DataKeeper::SaveListModes(Channel* chan, ListModeBase* lm, size_t index, ModesExts& currdata)
393 {
394         const ListModeBase::ModeList* list = lm->GetList(chan);
395         if (!list)
396                 return;
397
398         for (ListModeBase::ModeList::const_iterator i = list->begin(); i != list->end(); ++i)
399         {
400                 const ListModeBase::ListItem& listitem = *i;
401                 currdata.modelist.push_back(InstanceData(index, listitem.mask));
402         }
403 }
404
405 void DataKeeper::DoSaveChans()
406 {
407         ModesExts currdata;
408         std::vector<OwnedModesExts> currmemberdata;
409
410         const chan_hash& chans = ServerInstance->GetChans();
411         for (chan_hash::const_iterator i = chans.begin(); i != chans.end(); ++i)
412         {
413                 Channel* const chan = i->second;
414
415                 // Serialize channel modes
416                 for (size_t j = 0; j < handledmodes[MODETYPE_CHANNEL].size(); j++)
417                 {
418                         ModeHandler* mh = handledmodes[MODETYPE_CHANNEL][j].mh;
419                         ListModeBase* lm = mh->IsListModeBase();
420                         if (lm)
421                                 SaveListModes(chan, lm, j, currdata);
422                         else if (chan->IsModeSet(mh))
423                                 currdata.modelist.push_back(InstanceData(j, chan->GetModeParameter(mh)));
424                 }
425
426                 // Serialize all extensions attached to the Channel
427                 SaveExtensions(chan, currdata.extlist);
428
429                 // Serialize all extensions attached to and all modes set on all members of the channel
430                 SaveMemberData(chan, currmemberdata);
431
432                 // Same logic as in DoSaveUsers() plus we consider the modes and extensions of all members
433                 if ((!currdata.empty()) || (!currmemberdata.empty()))
434                 {
435                         chandatalist.push_back(ChanData(chan));
436                         chandatalist.back().swap(currdata);
437                         chandatalist.back().memberdatalist.swap(currmemberdata);
438                 }
439         }
440 }
441
442 void DataKeeper::SaveMemberData(Channel* chan, std::vector<OwnedModesExts>& memberdatalist)
443 {
444         ModesExts currdata;
445         const Channel::MemberMap& users = chan->GetUsers();
446         for (Channel::MemberMap::const_iterator i = users.begin(); i != users.end(); ++i)
447         {
448                 Membership* const memb = i->second;
449
450                 for (size_t j = 0; j < handledmodes[MODETYPE_CHANNEL].size(); j++)
451                 {
452                         ModeHandler* mh = handledmodes[MODETYPE_CHANNEL][j].mh;
453                         const PrefixMode* const pm = mh->IsPrefixMode();
454                         if ((pm) && (memb->HasMode(pm)))
455                                 currdata.modelist.push_back(InstanceData(j, memb->user->uuid)); // Need to pass the user's uuid to the mode parser to set the mode later
456                 }
457
458                 SaveExtensions(memb, currdata.extlist);
459
460                 // Same logic as in DoSaveUsers()
461                 if (!currdata.empty())
462                 {
463                         memberdatalist.push_back(OwnedModesExts(memb->user->uuid));
464                         memberdatalist.back().swap(currdata);
465                 }
466         }
467 }
468
469 void DataKeeper::RestoreMemberData(Channel* chan, const std::vector<ChanData::MemberData>& memberdatalist, Modes::ChangeList& modechange)
470 {
471         for (std::vector<ChanData::MemberData>::const_iterator i = memberdatalist.begin(); i != memberdatalist.end(); ++i)
472         {
473                 const ChanData::MemberData& md = *i;
474                 User* const user = ServerInstance->FindUUID(md.owner);
475                 if (!user)
476                 {
477                         ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "User %s is gone (while processing %s)", md.owner.c_str(), chan->name.c_str());
478                         continue;
479                 }
480
481                 Membership* const memb = chan->GetUser(user);
482                 if (!memb)
483                 {
484                         ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Member %s is no longer on channel %s", md.owner.c_str(), chan->name.c_str());
485                         continue;
486                 }
487
488                 RestoreObj(md, memb, MODETYPE_CHANNEL, modechange);
489         }
490 }
491
492 void DataKeeper::CreateModeList(ModeType modetype)
493 {
494         const ModeParser::ModeHandlerMap& modes = ServerInstance->Modes->GetModes(modetype);
495         for (ModeParser::ModeHandlerMap::const_iterator i = modes.begin(); i != modes.end(); ++i)
496         {
497                 ModeHandler* mh = i->second;
498                 if (mh->creator == mod)
499                         handledmodes[modetype].push_back(ProviderInfo(mh));
500         }
501 }
502
503 void DataKeeper::Save(Module* currmod)
504 {
505         this->mod = currmod;
506
507         const ExtensionManager::ExtMap& allexts = ServerInstance->Extensions.GetExts();
508         for (ExtensionManager::ExtMap::const_iterator i = allexts.begin(); i != allexts.end(); ++i)
509         {
510                 ExtensionItem* ext = i->second;
511                 if (ext->creator == mod)
512                         handledexts.push_back(ProviderInfo(ext));
513         }
514
515         CreateModeList(MODETYPE_USER);
516         DoSaveUsers();
517
518         CreateModeList(MODETYPE_CHANNEL);
519         DoSaveChans();
520
521         FOREACH_MOD_CUSTOM(*reloadevprov, ReloadModule::EventListener, OnReloadModuleSave, (mod, this->moddata));
522
523         ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Saved data about %lu users %lu chans %lu modules", (unsigned long)userdatalist.size(), (unsigned long)chandatalist.size(), (unsigned long)moddata.list.size());
524 }
525
526 void DataKeeper::VerifyServiceProvider(const ProviderInfo& service, const char* type)
527 {
528         const ServiceProvider* sp = service.extitem;
529         if (!sp)
530                 ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "%s \"%s\" is no longer available", type, service.itemname.c_str());
531         else if (sp->creator != mod)
532                 ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "%s \"%s\" is now handled by %s", type, service.itemname.c_str(), (sp->creator ? sp->creator->ModuleSourceFile.c_str() : "<core>"));
533 }
534
535 void DataKeeper::LinkModes(ModeType modetype)
536 {
537         std::vector<ProviderInfo>& list = handledmodes[modetype];
538         for (std::vector<ProviderInfo>::iterator i = list.begin(); i != list.end(); ++i)
539         {
540                 ProviderInfo& item = *i;
541                 item.mh = ServerInstance->Modes->FindMode(item.itemname, modetype);
542                 VerifyServiceProvider(item, (modetype == MODETYPE_USER ? "User mode" : "Channel mode"));
543         }
544 }
545
546 void DataKeeper::LinkExtensions()
547 {
548         for (std::vector<ProviderInfo>::iterator i = handledexts.begin(); i != handledexts.end(); ++i)
549         {
550                 ProviderInfo& item = *i;
551                 item.extitem = ServerInstance->Extensions.GetItem(item.itemname);
552                 VerifyServiceProvider(item.extitem, "Extension");
553         }
554 }
555
556 void DataKeeper::LinkSerializers()
557 {
558         for (std::vector<ProviderInfo>::iterator i = handledserializers.begin(); i != handledserializers.end(); ++i)
559         {
560                 ProviderInfo& item = *i;
561                 item.serializer = ServerInstance->Modules.FindDataService<ClientProtocol::Serializer>(item.itemname);
562                 VerifyServiceProvider(item.serializer, "Serializer");
563         }
564 }
565
566 void DataKeeper::Restore(Module* newmod)
567 {
568         this->mod = newmod;
569
570         // Find the new extension items
571         LinkExtensions();
572         LinkModes(MODETYPE_USER);
573         LinkModes(MODETYPE_CHANNEL);
574         LinkSerializers();
575
576         // Restore
577         DoRestoreUsers();
578         DoRestoreChans();
579         DoRestoreModules();
580
581         ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Restore finished");
582 }
583
584 void DataKeeper::Fail()
585 {
586         this->mod = NULL;
587
588         ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Restore failed, notifying modules");
589         DoRestoreModules();
590 }
591
592 void DataKeeper::RestoreObj(const OwnedModesExts& data, Extensible* extensible, ModeType modetype, Modes::ChangeList& modechange)
593 {
594         RestoreExtensions(data.extlist, extensible);
595         RestoreModes(data.modelist, modetype, modechange);
596 }
597
598 void DataKeeper::RestoreExtensions(const std::vector<InstanceData>& list, Extensible* extensible)
599 {
600         for (std::vector<InstanceData>::const_iterator i = list.begin(); i != list.end(); ++i)
601         {
602                 const InstanceData& id = *i;
603                 handledexts[id.index].extitem->FromInternal(extensible, id.serialized);
604         }
605 }
606
607 void DataKeeper::RestoreModes(const std::vector<InstanceData>& list, ModeType modetype, Modes::ChangeList& modechange)
608 {
609         for (std::vector<InstanceData>::const_iterator i = list.begin(); i != list.end(); ++i)
610         {
611                 const InstanceData& id = *i;
612                 modechange.push_add(handledmodes[modetype][id.index].mh, id.serialized);
613         }
614 }
615
616 bool DataKeeper::RestoreSerializer(size_t serializerindex, User* user)
617 {
618         if (serializerindex == UserData::UNUSED_INDEX)
619                 return true;
620
621         // The following checks are redundant
622         LocalUser* const localuser = IS_LOCAL(user);
623         if (!localuser)
624                 return true;
625         if (localuser->serializer != dummyserializer)
626                 return true;
627
628         const ProviderInfo& provinfo = handledserializers[serializerindex];
629         if (!provinfo.serializer)
630         {
631                 // Users cannot exist without a serializer
632                 ServerInstance->Users.QuitUser(user, "Serializer lost in reload");
633                 return false;
634         }
635
636         localuser->serializer = provinfo.serializer;
637         return true;
638 }
639
640 void DataKeeper::DoRestoreUsers()
641 {
642         ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Restoring user data");
643         Modes::ChangeList modechange;
644
645         for (std::vector<UserData>::const_iterator i = userdatalist.begin(); i != userdatalist.end(); ++i)
646         {
647                 const UserData& userdata = *i;
648                 User* const user = ServerInstance->FindUUID(userdata.owner);
649                 if (!user)
650                 {
651                         ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "User %s is gone", userdata.owner.c_str());
652                         continue;
653                 }
654
655                 // Attempt to restore serializer first, if it fails it's a fatal error and RestoreSerializer() quits them
656                 if (!RestoreSerializer(userdata.serializerindex, user))
657                         continue;
658
659                 RestoreObj(userdata, user, MODETYPE_USER, modechange);
660                 ServerInstance->Modes.Process(ServerInstance->FakeClient, NULL, user, modechange, ModeParser::MODE_LOCALONLY);
661                 modechange.clear();
662         }
663 }
664
665 void DataKeeper::DoRestoreChans()
666 {
667         ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Restoring channel data");
668         Modes::ChangeList modechange;
669
670         for (std::vector<ChanData>::const_iterator i = chandatalist.begin(); i != chandatalist.end(); ++i)
671         {
672                 const ChanData& chandata = *i;
673                 Channel* const chan = ServerInstance->FindChan(chandata.owner);
674                 if (!chan)
675                 {
676                         ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Channel %s not found", chandata.owner.c_str());
677                         continue;
678                 }
679
680                 RestoreObj(chandata, chan, MODETYPE_CHANNEL, modechange);
681                 // Process the mode change before applying any prefix modes
682                 ServerInstance->Modes.Process(ServerInstance->FakeClient, chan, NULL, modechange, ModeParser::MODE_LOCALONLY);
683                 modechange.clear();
684
685                 // Restore all member data
686                 RestoreMemberData(chan, chandata.memberdatalist, modechange);
687                 ServerInstance->Modes.Process(ServerInstance->FakeClient, chan, NULL, modechange, ModeParser::MODE_LOCALONLY);
688                 modechange.clear();
689         }
690 }
691
692 void DataKeeper::DoRestoreModules()
693 {
694         for (ReloadModule::CustomData::List::iterator i = moddata.list.begin(); i != moddata.list.end(); ++i)
695         {
696                 ReloadModule::CustomData::Data& data = *i;
697                 ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Calling module data handler %p", (void*)data.handler);
698                 data.handler->OnReloadModuleRestore(mod, data.data);
699         }
700 }
701
702 } // namespace ReloadModule
703
704 class ReloadAction : public ActionBase
705 {
706         Module* const mod;
707         const std::string uuid;
708         const std::string passedname;
709
710  public:
711         ReloadAction(Module* m, const std::string& uid, const std::string& passedmodname)
712                 : mod(m)
713                 , uuid(uid)
714                 , passedname(passedmodname)
715         {
716         }
717
718         void Call() CXX11_OVERRIDE
719         {
720                 ReloadModule::DataKeeper datakeeper;
721                 datakeeper.Save(mod);
722
723                 std::string name = mod->ModuleSourceFile;
724                 ServerInstance->Modules->DoSafeUnload(mod);
725                 ServerInstance->GlobalCulls.Apply();
726                 bool result = ServerInstance->Modules->Load(name);
727
728                 if (result)
729                 {
730                         Module* newmod = ServerInstance->Modules->Find(name);
731                         datakeeper.Restore(newmod);
732                 }
733                 else
734                         datakeeper.Fail();
735
736                 ServerInstance->SNO->WriteGlobalSno('a', "RELOAD MODULE: %s %ssuccessfully reloaded", passedname.c_str(), result ? "" : "un");
737                 User* user = ServerInstance->FindUUID(uuid);
738                 if (user)
739                 {
740                         int numeric = result ? RPL_LOADEDMODULE : ERR_CANTUNLOADMODULE;
741                         user->WriteNumeric(numeric, passedname, InspIRCd::Format("Module %ssuccessfully reloaded.", (result ? "" : "un")));
742                 }
743
744                 ServerInstance->GlobalCulls.AddItem(this);
745         }
746 };
747
748 CmdResult CommandReloadmodule::Handle(User* user, const Params& parameters)
749 {
750         Module* m = ServerInstance->Modules->Find(parameters[0]);
751         if (m == creator)
752         {
753                 user->WriteNumeric(ERR_CANTUNLOADMODULE, parameters[0], "You cannot reload core_reloadmodule (unload and load it)");
754                 return CMD_FAILURE;
755         }
756
757         if (creator->dying)
758                 return CMD_FAILURE;
759
760         if ((m) && (ServerInstance->Modules.CanUnload(m)))
761         {
762                 ServerInstance->AtomicActions.AddAction(new ReloadAction(m, user->uuid, parameters[0]));
763                 return CMD_SUCCESS;
764         }
765         else
766         {
767                 user->WriteNumeric(ERR_CANTUNLOADMODULE, parameters[0], "Could not find module by that name");
768                 return CMD_FAILURE;
769         }
770 }
771
772 class CoreModReloadmodule : public Module
773 {
774  private:
775         CommandReloadmodule cmd;
776
777  public:
778         CoreModReloadmodule()
779                 : cmd(this)
780         {
781         }
782
783         Version GetVersion() CXX11_OVERRIDE
784         {
785                 return Version("Provides the RELOADMODULE command", VF_CORE | VF_VENDOR);
786         }
787 };
788
789 MODULE_INIT(CoreModReloadmodule)