+ if (res->error.Id() == NO_ERROR)
+ {
+ ServerInstance->Log(DEBUG, "Associated query ID %lu with user %s", res->id, user->nick);
+ ServerInstance->Log(DEBUG, "Got result with %d rows and %d columns", res->Rows(), res->Cols());
+
+ if (res->Rows())
+ {
+ /* We got a row in the result, this means there was a record for the oper..
+ * now we just need to check if their host matches, and if it does then
+ * oper them up.
+ *
+ * We now (previous versions of the module didn't) support multiple SQL
+ * rows per-oper in the same way the config file does, all rows will be tried
+ * until one is found which matches. This is useful to define several different
+ * hosts for a single oper.
+ *
+ * The for() loop works as SQLresult::GetRowMap() returns an empty map when there
+ * are no more rows to return.
+ */
+
+ for (SQLfieldMap& row = res->GetRowMap(); row.size(); row = res->GetRowMap())
+ {
+ ServerInstance->Log(DEBUG, "Trying to oper user %s with username = '%s', passhash = '%s', hostname = '%s', type = '%s'", user->nick, row["username"].d.c_str(), row["password"].d.c_str(), row["hostname"].d.c_str(), row["type"].d.c_str());
+
+ if (OperUser(user, row["username"].d, row["password"].d, row["hostname"].d, row["type"].d))
+ {
+ /* If/when one of the rows matches, stop checking and return */
+ return SQLSUCCESS;
+ }
+ }
+ }
+ else
+ {
+ /* No rows in result, this means there was no oper line for the user,
+ * we should have already checked the o:lines so now we need an
+ * "insufficient awesomeness" (invalid credentials) error
+ */
+
+ user->WriteServ( "491 %s :Invalid oper credentials", user->nick);
+ Srv->WriteOpers("*** WARNING! Failed oper attempt by %s!%s@%s!", user->nick, user->ident, user->host);
+ ServerInstance->Log(DEFAULT,"OPER: Failed oper attempt by %s!%s@%s: user, host or password did not match.", user->nick, user->ident, user->host);
+ }
+ }
+ else