+ else if (command == "METADATA")
+ {
+ // Drop TS for channel METADATA, translate METADATA operquit into an OPERQUIT command
+ // :sid METADATA #target TS extname ...
+ // A B C D
+ if (b == std::string::npos)
+ return;
+
+ std::string::size_type c = line.find(' ', b + 1);
+ if (c == std::string::npos)
+ return;
+
+ std::string::size_type d = line.find(' ', c + 1);
+ if (d == std::string::npos)
+ return;
+
+ if (line[b + 1] == '#')
+ {
+ // We're sending channel metadata
+ line.erase(c, d-c);
+ }
+ else if (!line.compare(c, d-c, " operquit", 9))
+ {
+ // ":22D METADATA 22DAAAAAX operquit :message" -> ":22DAAAAAX OPERQUIT :message"
+ line = ":" + line.substr(b+1, c-b) + "OPERQUIT" + line.substr(d);
+ }
+ }
+ else if (command == "FTOPIC")
+ {
+ // Drop channel TS for FTOPIC
+ // :sid FTOPIC #target TS TopicTS setter :newtopic
+ // A B C D E F
+ // :uid FTOPIC #target TS TopicTS :newtopic
+ // A B C D E
+ if (b == std::string::npos)
+ return;
+
+ std::string::size_type c = line.find(' ', b + 1);
+ if (c == std::string::npos)
+ return;
+
+ std::string::size_type d = line.find(' ', c + 1);
+ if (d == std::string::npos)
+ return;
+
+ std::string::size_type e = line.find(' ', d + 1);
+ if (line[e+1] == ':')
+ {
+ line.erase(c, e-c);
+ line.erase(a+1, 1);
+ }
+ else
+ line.erase(c, d-c);
+ }
+ else if ((command == "PING") || (command == "PONG"))
+ {
+ // :22D PING 20D
+ if (line.length() < 13)
+ return;
+
+ // Insert the source SID (and a space) between the command and the first parameter
+ line.insert(10, line.substr(1, 4));
+ }
+ else if (command == "OPERTYPE")
+ {
+ std::string::size_type colon = line.find(':', b);
+ if (colon != std::string::npos)
+ {
+ for (std::string::iterator i = line.begin()+colon; i != line.end(); ++i)
+ {
+ if (*i == ' ')
+ *i = '_';
+ }
+ line.erase(colon, 1);
+ }
+ }
+ else if (command == "INVITE")
+ {
+ // :22D INVITE 22DAAAAAN #chan TS ExpirationTime
+ // A B C D E
+ if (b == std::string::npos)
+ return;
+
+ std::string::size_type c = line.find(' ', b + 1);
+ if (c == std::string::npos)
+ return;
+
+ std::string::size_type d = line.find(' ', c + 1);
+ if (d == std::string::npos)
+ return;
+
+ std::string::size_type e = line.find(' ', d + 1);
+ // If there is no expiration time then everything will be erased from 'd'
+ line.erase(d, e-d);
+ }
+ else if (command == "FJOIN")
+ {
+ // Strip membership ids
+ // :22D FJOIN #chan 1234 +f 4:3 :o,22DAAAAAB:15 o,22DAAAAAA:15
+ // :22D FJOIN #chan 1234 +f 4:3 o,22DAAAAAB:15
+ // :22D FJOIN #chan 1234 +Pf 4:3 :
+
+ // If the last parameter is prefixed by a colon then it's a userlist which may have 0 or more users;
+ // if it isn't, then it is a single member
+ std::string::size_type spcolon = line.find(" :");
+ if (spcolon != std::string::npos)
+ {
+ spcolon++;
+ // Loop while there is a ':' in the userlist, this is never true if the channel is empty
+ std::string::size_type pos = std::string::npos;
+ while ((pos = line.rfind(':', pos-1)) > spcolon)
+ {
+ // Find the next space after the ':'
+ std::string::size_type sp = line.find(' ', pos);
+ // Erase characters between the ':' and the next space after it, including the ':' but not the space;
+ // if there is no next space, everything will be erased between pos and the end of the line
+ line.erase(pos, sp-pos);
+ }
+ }
+ else
+ {
+ // Last parameter is a single member
+ std::string::size_type sp = line.rfind(' ');
+ std::string::size_type colon = line.find(':', sp);
+ line.erase(colon);
+ }
+ }
+ else if (command == "KICK")