Esempio n. 1
0
int csc_dorecover(void *source, int cargc, char **cargv) {
  nick *sender=source,*np;
  reguser *rup;
  regchanuser *rcup;
  regchan *rcp;
  chanindex *cip;
  unsigned long *lp;
  int i;
  modechanges changes;
  
  if (cargc<1) {
    chanservstdmessage(sender, QM_NOTENOUGHPARAMS, "recover");
    return CMD_ERROR;
  }

  if (!(cip=cs_checkaccess(sender, cargv[0], CA_MASTERPRIV, NULL, "recover",0, 0)))
    return CMD_ERROR;

  rcp=cip->exts[chanservext];

  if (cip->channel) {
    localsetmodeinit(&changes, cip->channel, chanservnick);

    /* clearchan */
    localdosetmode_key(&changes, NULL, MCB_DEL);
    localdosetmode_simple(&changes, 0, cip->channel->flags);
    cs_docheckchanmodes(cip->channel, &changes);

    /* unbanall */
    while (cip->channel->bans) {
      localdosetmode_ban(&changes, bantostring(cip->channel->bans), MCB_DEL);
    }

    /* remove the registered bans that match on me */
    cs_unbanfn(sender, cip, nickmatchban_peerthroughhidehost, sender, 1, 0);

    /* deopall */
    for (i=0,lp=cip->channel->users->content;
	 i<cip->channel->users->hashsize;i++,lp++) {
      if (*lp!=nouser && (*lp & CUMODE_OP)) {
	if (!(np=getnickbynumeric(*lp)) || 
	    (!IsService(np) && (!(rup=getreguserfromnick(np)) || 
	    !(rcup=findreguseronchannel(rcp, rup)) || !(CUHasOpPriv(rcup)) ||
	    !(CUIsProtect(rcup) || CIsProtect(rcp))))) {
	  localdosetmode_nick(&changes, np, MC_DEOP);
	}
      }
    }

    localsetmodeflush(&changes, 1);
  }

  cs_log(sender,"RECOVER %s",cip->name->content);
  chanservstdmessage(sender, QM_DONE);
  return CMD_OK;
}     
Esempio n. 2
0
void csdb_doaccounthistory_real(DBConn *dbconn, void *arg) {
  nick *np=getnickbynumeric((unsigned long)arg);
  reguser *rup;
  char *oldpass, *newpass, *oldemail, *newemail;
  time_t changetime;
  DBResult *pgres;
  int count=0;
  char tbuf[TIMELEN];

  if(!dbconn)
    return;

  pgres=dbgetresult(dbconn);

  if (!dbquerysuccessful(pgres)) {
    Error("chanserv", ERR_ERROR, "Error loading account history data.");
    return;
  }

  if (dbnumfields(pgres) != 7) {
    Error("chanserv", ERR_ERROR, "Account history data format error.");
    dbclear(pgres);
    return;
  }

  if (!np) {
    dbclear(pgres);
    return;
  }

  if (!(rup=getreguserfromnick(np)) || !UHasOperPriv(rup)) {
    Error("chanserv", ERR_ERROR, "No reguser pointer or oper privs in account history.");
    dbclear(pgres);
    return;
  }

  /* @TIMELEN */
  chanservsendmessage(np, "Number: Time:               Old password:  New password:  Old email:                     New email:");
  while(dbfetchrow(pgres)) {
    /*userID=strtoul(dbgetvalue(pgres, 0), NULL, 10);*/
    changetime=strtoul(dbgetvalue(pgres, 1), NULL, 10);
    /*authtime=strtoul(dbgetvalue(pgres, 2), NULL, 10);*/
    oldpass=dbgetvalue(pgres, 3);
    newpass=dbgetvalue(pgres, 4);
    oldemail=dbgetvalue(pgres, 5);
    newemail=dbgetvalue(pgres, 6);
    q9strftime(tbuf, sizeof(tbuf), changetime);
    chanservsendmessage(np, "#%-6d %-19s %-14s %-14s %-30s %s", ++count, tbuf, oldpass, newpass, oldemail, newemail); /* @TIMELEN */
  }
  chanservstdmessage(np, QM_ENDOFLIST);

  dbclear(pgres);
}
Esempio n. 3
0
void notice_free(searchCtx *ctx, struct searchNode *thenode) {
  struct notice_localdata *localdata;
  nick *np, *nnp;
  chanindex *cip, *ncip;
  int i, j;
  unsigned int nickmarker;

  localdata = thenode->localdata;

  if (ctx->searchcmd == reg_chansearch) {
    nickmarker=nextnickmarker();
    for (i=0;i<CHANNELHASHSIZE;i++) {
      for (cip=chantable[i];cip;cip=ncip) {
        ncip = cip->next;
        if (cip != NULL && cip->channel != NULL && cip->marker == localdata->marker) {
          for (j=0;j<cip->channel->users->hashsize;j++) {
            if (cip->channel->users->content[j]==nouser)
              continue;
    
            if ((np=getnickbynumeric(cip->channel->users->content[j])))
              np->marker=nickmarker;
          }
        }
      }
    }
    for (i=0;i<NICKHASHSIZE;i++) {
      for(np=nicktable[i];np;np=nnp) {
        nnp = np->next;
        if (np->marker == nickmarker)
          controlnotice(np, "%s", localdata->message);
      }
    }
  }
  else {
    for (i=0;i<NICKHASHSIZE;i++) {
      for (np=nicktable[i];np;np=nnp) {
        nnp = np->next;
        if (np->marker == localdata->marker)
         controlnotice(np, "%s", localdata->message);
      }
    }
  }
  /* notify opers of the action */
  ctx->wall(NL_BROADCASTS, "%s/%s sent the following message to %d %s: %s", senderNSExtern->nick, senderNSExtern->authname, localdata->count, localdata->count != 1 ? "users" : "user", localdata->message);
  free(localdata);
  free(thenode);
}
Esempio n. 4
0
void *authedpct_exe(searchCtx *ctx, struct searchNode *thenode, void *theinput) {
  int i;
  int j=0;
  nick *np;
  chanindex *cip = (chanindex *)theinput;

  if (!cip->channel)
    return (void *)0;
  
  for (i=0;i<cip->channel->users->hashsize;i++) {
    if (cip->channel->users->content[i]==nouser)
      continue;
    
    if ((np=getnickbynumeric(cip->channel->users->content[i])) && IsAccount(np))
      j++;
  }

  return (void *)(long)((j * 100) / cip->channel->users->totalusers);
}  
Esempio n. 5
0
int csc_dodeopall(void *source, int cargc, char **cargv) {
  nick *sender=source,*np;
  reguser *rup;
  regchanuser *rcup;
  regchan *rcp;
  chanindex *cip;
  unsigned long *lp;
  int i;
  modechanges changes;
  
  if (cargc<1) {
    chanservstdmessage(sender, QM_NOTENOUGHPARAMS, "deopall");
    return CMD_ERROR;
  }

  if (!(cip=cs_checkaccess(sender, cargv[0], CA_MASTERPRIV, NULL, "deopall",0, 0)))
    return CMD_ERROR;

  rcp=cip->exts[chanservext];

  if (cip->channel) {
    localsetmodeinit(&changes, cip->channel, chanservnick);

    for (i=0,lp=cip->channel->users->content;
	 i<cip->channel->users->hashsize;i++,lp++) {
      if (*lp!=nouser && (*lp & CUMODE_OP)) {
	if (!(np=getnickbynumeric(*lp)) || 
	    (!IsService(np) && (!(rup=getreguserfromnick(np)) || 
	    !(rcup=findreguseronchannel(rcp, rup)) || !(CUHasOpPriv(rcup)) ||
	    !(CUIsProtect(rcup) || CIsProtect(rcp))))) {
	  localdosetmode_nick(&changes, np, MC_DEOP);
	}
      }
    }

    localsetmodeflush(&changes, 1);
  }

  cs_log(sender,"DEOPALL %s",cip->name->content);
  chanservstdmessage(sender, QM_DONE);
  return CMD_OK;
}     
Esempio n. 6
0
int dofsck(void *source, int cargc, char **cargv) {
  int i,j;
  nick *sender=source, *np, *np2;
  host *hp;
  realname *rnp;
  unsigned int nickmarker;
  int errors=0;
  unsigned int nummask,mnum;

  /* Start off with strict nick consistency checks.. */

  controlreply(sender,"- Performing nickname checks"); 

  nickmarker=nextnickmarker();

  for(i=0;i<HOSTHASHSIZE;i++)
    for(hp=hosttable[i];hp;hp=hp->next)
      hp->marker=0;
  
  for(i=0;i<REALNAMEHASHSIZE;i++)
    for(rnp=realnametable[i];rnp;rnp=rnp->next)
      rnp->marker=0;

  controlreply(sender," - Scanning nick hash table");
  
  for (i=0;i<NICKHASHSIZE;i++) {
    for(np=nicktable[i];np;np=np->next) {
      if (np->marker==nickmarker) {
        controlreply(sender, "ERROR: bumped into the same nick %s/%s twice in hash table.",longtonumeric(np->numeric,5),np->nick);
        errors++;
      }
      
      /* Mark this nick so we can check we found them all */
      np->marker=nickmarker;

      /* Check that we can find this nick with the lookup functions */
      if (getnickbynick(np->nick) != np) {
	controlreply(sender, "ERROR: can't find %s/%s using getnickbynick().",
		     longtonumeric(np->numeric,5),np->nick);
	errors++;
      }

      if (getnickbynumeric(np->numeric) != np) {
	controlreply(sender, "ERROR: can't find %s/%s using getnickbynumeric().",
		     longtonumeric(np->numeric,5),np->nick);
	errors++;
      }

      /* Check that the nick appears in the list of nicks using its host */
      if (findhost(np->host->name->content) != np->host) {
	controlreply(sender, "ERROR: can't find %s/%s's host (%s) using findhost().",
		     longtonumeric(np->numeric,5),np->nick,np->host->name->content);
	errors++;
      }

      for(np2=np->host->nicks;np2;np2=np2->nextbyhost)
	if (np2==np)
	  break;

      if (!np2) {
	controlreply(sender, "ERROR: can't find %s/%s (host=%s) on the host users list.",
		     longtonumeric(np->numeric,5),np->nick,np->host->name->content);
	errors++;
      }

      np->host->marker++;

      /* Same for realnames */
      if (findrealname(np->realname->name->content) != np->realname) {
	controlreply(sender, "ERROR: can't find %s/%s's realname (%s) using findrealname().",
		     longtonumeric(np->numeric,5),np->nick,np->realname->name->content);
	errors++;
      }

      for(np2=np->realname->nicks;np2;np2=np2->nextbyrealname)
	if (np2==np)
	  break;

      if (!np2) {
	controlreply(sender, 
		     "ERROR: can't find %s/%s (realname=%s) on the realname users list.",
		     longtonumeric(np->numeric,5),np->nick,np->realname->name->content);
	errors++;
      }

      np->realname->marker++;

      if (IsAccount(np) && !np->authname[0]) {
	controlreply(sender, "ERROR: nick %s/%s is +r but no authname stored.",
		     longtonumeric(np->numeric,5),np->nick);
	errors++;
      }

/*
      if (!IsAccount(np) && np->authname[0]) {
	controlreply(sender, "ERROR: nick %s/%s is -r but carries authname '%s'.",
		     longtonumeric(np->numeric,5),np->nick,np->authname);
	errors++;
      }
*/

      if (IsSetHost(np) && (!np->sethost || !np->shident)) {
	controlreply(sender, "ERROR: nick %s/%s is +h but nick or hostname not set.",
		     longtonumeric(np->numeric,5),np->nick);
	errors++;
      }

      if (!IsSetHost(np) && (np->sethost || np->shident)) {
	controlreply(sender, "ERROR: nick %s/%s is -h but has nick or hostname set.",
		     longtonumeric(np->numeric,5),np->nick);
	errors++;
      }

    }
  }

  controlreply(sender," - Scanning server user tables");
      
  for(i=0;i<MAXSERVERS;i++) {
    if (serverlist[i].linkstate != LS_INVALID) {
      nummask=((MAXSERVERS-1)<<18) | serverlist[i].maxusernum;
      for (j=0;j<=serverlist[i].maxusernum;j++) {
	if ((np=servernicks[i][j])) {
	  mnum=(i<<18) | j;
	  if ((np->numeric & nummask) != mnum) {
	    controlreply(sender, "ERROR: nick %s/%s has wrong masked numeric.",longtonumeric(np->numeric,5),np->nick);
	    errors++;
          }
	  if (np->marker != nickmarker) {
	    controlreply(sender, "ERROR: nick %s/%s in server user table but not hash!",
			 longtonumeric(np->numeric,5),np->nick);
	    errors++;
	  }
	  np->marker=0;
	}
      }
    }
  }

  controlreply(sender," - Scanning host and realname tables");
  
  for (i=0;i<HOSTHASHSIZE;i++) {
    for (hp=hosttable[i];hp;hp=hp->next) {

      /* Check that the user counts match up */
      if (hp->clonecount != hp->marker) {
	controlreply(sender,
		     "ERROR: host %s has inconsistent clone count (stored=%d, measured=%u)",
		     hp->name->content,hp->clonecount,hp->marker);
	errors++;
      }
      
      for (np=hp->nicks;np;np=np->nextbyhost) {
	if (np->host != hp) {
	  controlreply(sender, 
		       "ERROR: nick %s/%s is in list for wrong host "
		       "(in list for %s, actual host %s).",
		       longtonumeric(np->numeric,5),np->nick,hp->name->content,
		       np->host->name->content);
	  errors++;
	}
      }
      
      hp->marker=0;
    }
  }

  for (i=0;i<REALNAMEHASHSIZE;i++) {
    for (rnp=realnametable[i];rnp;rnp=rnp->next) {
      if (rnp->usercount != rnp->marker) {
	controlreply(sender,
		     "ERROR: realname '%s' has inconsistent clone count "
		     "(stored=%d, measured=%d).",
		     rnp->name->content,rnp->usercount,rnp->marker);
	errors++;
      }

      for (np=rnp->nicks;np;np=np->nextbyrealname) {
	if (np->realname != rnp) {
	  controlreply(sender, 
		       "ERROR: nick %s/%s is in list for wrong realname "
		       "(in list for '%s', actual realname '%s').",
		       longtonumeric(np->numeric,5),np->nick,
		       rnp->name->content, np->realname->name->content);
	  errors++;
	}
      }
      
      rnp->marker=0;
    }
  }

  if (errors) 
    controlreply(sender,"All checks complete. %d errors found.",errors);
  else 
    controlreply(sender,"All checks complete. No errors found.");

  return CMD_OK;
}
Esempio n. 7
0
void csc_dorollbackchan_real(DBConn *dbconn, void *arg) {
  nick *np=getnickbynumeric((unsigned long)arg);
  reguser *rup, *crup1, *crup2;
  chanindex *cip = NULL;
  regchan *rcp=NULL;
  regchanuser *rcup;
  unsigned int userID, channelID, targetID;
  time_t changetime, authtime;
  flag_t oldflags, newflags;
  DBResult *pgres;
  int j, newuser;
  char fbuf[18];

  if(!dbconn)
    return;

  pgres=dbgetresult(dbconn);

  if (!dbquerysuccessful(pgres)) {
    Error("chanserv", ERR_ERROR, "Error loading chanlev history data.");
    return;
  }

  if (dbnumfields(pgres) != 7) {
    Error("chanserv", ERR_ERROR, "Chanlev history data format error.");
    dbclear(pgres);
    return;
  }

  if (!np) {
    Error("chanserv", ERR_ERROR, "No nick pointer in rollback.");
    dbclear(pgres);
    return;
  }
  if (!(rup=getreguserfromnick(np)) || !UHasOperPriv(rup)) {
    Error("chanserv", ERR_ERROR, "No reguser pointer or oper privs in rollback.");
    dbclear(pgres);
    return;
  }

  while(dbfetchrow(pgres)) {
    userID=strtoul(dbgetvalue(pgres, 0), NULL, 10);
    channelID=strtoul(dbgetvalue(pgres, 1), NULL, 10);

    if (!rcp) {
      for (j=0; j<CHANNELHASHSIZE && !rcp; j++) {
        for (cip=chantable[j]; cip && !rcp; cip=cip->next) {
          if (!cip->exts[chanservext])
            continue;

          if (((regchan*)cip->exts[chanservext])->ID == channelID)
            rcp=(regchan*)cip->exts[chanservext];
        }
      }

      if (!rcp) {
        Error("chanserv", ERR_ERROR, "No regchan pointer or oper privs in rollback.");
        dbclear(pgres);
        return;
      }

      cip=rcp->index;

      chanservsendmessage(np, "Attempting to roll back %s:", cip->name->content);
    }
    targetID=strtoul(dbgetvalue(pgres, 2), NULL, 10);
    changetime=strtoul(dbgetvalue(pgres, 3), NULL, 10);
    authtime=strtoul(dbgetvalue(pgres, 4), NULL, 10);
    oldflags=strtoul(dbgetvalue(pgres, 5), NULL, 10);
    newflags=strtoul(dbgetvalue(pgres, 6), NULL, 10);
    strncpy(fbuf, printflags(newflags, rcuflags), 17);
    fbuf[17]='\0';
    crup1=findreguserbyID(userID);
    crup2=findreguserbyID(targetID);

    if (!crup2) {
      chanservsendmessage(np, "Affected user (ID: %d) is no longer in database, continuing...", targetID);
      continue;
    }

    if (!(rcup=findreguseronchannel(rcp, crup2))) {
      rcup=getregchanuser();
      rcup->user=crup2;
      rcup->chan=rcp;
      rcup->flags=0;
      rcup->changetime=time(NULL);
      rcup->usetime=0;
      rcup->info=NULL;
      newuser=1;
    }
    else
      newuser=0;
    csdb_chanlevhistory_insert(rcp, np, rcup->user, rcup->flags, oldflags);
    rcup->flags=oldflags;
    chanservsendmessage(np, "%s user flags for %s (%s -> %s)", newflags?oldflags?"Restoring":"Deleting":"Readding",
      crup2->username, fbuf, printflags(oldflags, rcuflags));

    if (rcup->flags) {
      if (newuser) {
        addregusertochannel(rcup);
        csdb_createchanuser(rcup);
      }
      else
        csdb_updatechanuser(rcup);
    }
    else {
      if (!newuser) {
        csdb_deletechanuser(rcup);
        delreguserfromchannel(rcp, crup2);
      }

      freesstring(rcup->info);
      freeregchanuser(rcup);
      rcup=NULL;

      for (j=0; j<REGCHANUSERHASHSIZE; j++)
        if (rcp->regusers[j])
          break;

      if (j==REGCHANUSERHASHSIZE) {
        cs_log(np, "DELCHAN %s (Cleared chanlev from rollback)", cip->name->content);
        chanservsendmessage(np, "Rollback cleared chanlev list, channel deleted.");
        rcp=NULL;
      }
    }
  }
  chanservstdmessage(np, QM_DONE);

  dbclear(pgres);
}
Esempio n. 8
0
void gline_free(searchCtx *ctx, struct searchNode *thenode) {
  struct gline_localdata *localdata;
  nick *np, *nnp;
  chanindex *cip, *ncip;
  whowas *ww;
  int i, j, hits, safe=0;
  time_t ti = time(NULL);
  glinebuf gbuf;

  localdata = thenode->localdata;

  if (localdata->count > NSMAX_GLINE_LIMIT) {
    /* need to warn the user that they have just tried to twat half the network ... */
    ctx->reply(senderNSExtern, "Warning: your pattern matches too many users (%d) - nothing done.", localdata->count);
    free(localdata);
    free(thenode);
    return;
  }

  glinebufinit(&gbuf, 0);

  if (ctx->searchcmd == reg_chansearch) {
    for (i=0;i<CHANNELHASHSIZE;i++) {
      for (cip=chantable[i];cip;cip=ncip) {
        ncip = cip->next;
        if (cip != NULL && cip->channel != NULL && cip->marker == localdata->marker) {
          for (j=0;j<cip->channel->users->hashsize;j++) {
            if (cip->channel->users->content[j]==nouser)
              continue;
    
            if ((np=getnickbynumeric(cip->channel->users->content[j]))) {
              if(!glineuser(&gbuf, np, localdata, ti))
                safe++;
            }
          }
        }
      }
    }
  } else if (ctx->searchcmd == reg_nicksearch) {
    for (i=0;i<NICKHASHSIZE;i++) {
      for (np=nicktable[i];np;np=nnp) {
        nnp = np->next;
        if (np->marker == localdata->marker) {
          if(!glineuser(&gbuf, np, localdata, ti))
            safe++;
        }
      }
    }
  } else {
    for (i = whowasoffset; i < whowasoffset + whowasmax; i++) {
      ww = &whowasrecs[i % whowasmax];

      if (ww->type == WHOWAS_UNUSED)
        continue;

      if (ww->marker == localdata->marker) {
        if(!glineuser(&gbuf, &ww->nick, localdata, ti))
          safe++;
      }
    }
  }

  glinebufcounthits(&gbuf, &hits, NULL);
  glinebufcommit(&gbuf, 1);

  if (safe)
    ctx->reply(senderNSExtern, "Warning: your pattern matched privileged users (%d in total) - these have not been touched.", safe);
  /* notify opers of the action */
  ctx->wall(NL_GLINES, "%s/%s glined %d %s via %s for %s [%d untouched].", senderNSExtern->nick, senderNSExtern->authname, (localdata->count - safe), 
    (localdata->count - safe) != 1 ? "users" : "user", (ctx->searchcmd == reg_chansearch) ? "chansearch" : "nicksearch", longtoduration(localdata->duration, 1), safe);
  free(localdata);
  free(thenode);
}
Esempio n. 9
0
hchannel *hchannel_add(const char *cname)
{
    channel *cp;
    hchannel *hchan;

    cp = findchannel((char*)cname);
    if (!cp)
    {
        localcreatechannel(helpmodnick, (char*)cname);
        cp = findchannel((char*)cname);
    }
    else
    {
        localjoinchannel(helpmodnick, cp);
        localgetops(helpmodnick, cp);
    }

    hchan = (hchannel*)malloc(sizeof(hchannel));

    hchan->welcome[0] = '\0';
    hchan->real_channel = cp;
    hchan->flags = H_CHANFLAGS_DEFAULT;
    hchan->channel_users = NULL;
    hchan->channel_hterms = NULL;
    hchan->max_idle = 5 * HDEF_m;
    hchan->topic = NULL;
    hchan->report_to = NULL;

    hchan->autoqueue = 0;
    hchan->jf_control = time(NULL);
    hchan->lc_profile = NULL;
    hchan->censor = NULL;

    hchan->htickets = NULL;
    hchan->ticket_message = NULL;

    hchan->last_activity = time(NULL);
    hchan->last_staff_activity = time(NULL);
    hchan->stats = get_hstat_channel();

    hchan->next = hchannels;
    hchannels = hchan;

    {
        int i;
        nick *nck;
        huser *husr;
        huser_channel *tmp;
        for (i=0;i < hchan->real_channel->users->hashsize;i++)
        {
            nck = getnickbynumeric(hchan->real_channel->users->content[i]);
            if (!nck) /* it's a hash, not an array */
                continue;

            if ((husr = huser_get(nck)) == NULL)
                husr = huser_add(nck);

	    tmp = huser_add_channel(husr, hchan);
            hchannel_add_user(hchan, husr);

            if (hchan->real_channel->users->content[i] & CUMODE_OP)
                tmp->flags |= HCUMODE_OP;
            if (hchan->real_channel->users->content[i] & CUMODE_VOICE)
                tmp->flags |= HCUMODE_VOICE;
        }
    }
    return hchan;
}
Esempio n. 10
0
int handleclearmodemsg(void *source, int cargc, char **cargv) {
  channel *cp;
  void *harg[4];
  nick *np, *target;
  char *mcp;
  unsigned long usermask=0;
  int i;
  int changes=0;

  if (cargc<2) {
    return CMD_OK;
  }

  if ((cp=findchannel(cargv[0]))==NULL) {
    /* No channel, abort */
    Error("channel",ERR_WARNING,"Mode change on non-existent channel %s",cargv[0]);
    return CMD_OK;
  }

  if (((char *)source)[2]=='\0') {
    /* Server mode change? (I don't think servers are allowed to do CLEARMODE) */
    np=NULL;
  } else if ((np=getnickbynumericstr((char *)source))==NULL) {
    /* No sender, continue but moan */
    Error("channel",ERR_WARNING,"Mode change by non-existent user %s on channel %s",(char *)source,cp->index->name->content);
  }
             
  harg[0]=cp;
  harg[1]=np;
  harg[3]=(void *)(long)(cp->flags);

  for (mcp=cargv[1];*mcp;mcp++) {
    switch (*mcp) {
      case 'o':
        usermask |= CUMODE_OP;
	changes |= MODECHANGE_USERS;
        break;
      
      case 'v':
        usermask |= CUMODE_VOICE;
	changes |= MODECHANGE_USERS;
        break;
        
      case 'n':
        ClearNoExtMsg(cp);
	changes |= MODECHANGE_MODES;
        break;
        
      case 't':
        ClearTopicLimit(cp);
	changes |= MODECHANGE_MODES;
        break;
      
      case 's':
        ClearSecret(cp);
	changes |= MODECHANGE_MODES;
        break;
        
      case 'p':
        ClearPrivate(cp);
	changes |= MODECHANGE_MODES;
        break;
        
      case 'i':
        ClearInviteOnly(cp);
	changes |= MODECHANGE_MODES;
        break;
        
      case 'm':
        ClearModerated(cp);
	changes |= MODECHANGE_MODES;
        break;
        
      case 'c':
        ClearNoColour(cp);
	changes |= MODECHANGE_MODES;
        break;
        
      case 'C':
        ClearNoCTCP(cp);
	changes |= MODECHANGE_MODES;
        break;
        
      case 'r':
        ClearRegOnly(cp);
	changes |= MODECHANGE_MODES;
        break;
      
      case 'D':
        ClearDelJoins(cp);
	changes |= MODECHANGE_MODES;
        break;

      case 'u':
        ClearNoQuitMsg(cp);
        changes |= MODECHANGE_MODES;
	break;

      case 'N':
        ClearNoNotice(cp);
        changes |= MODECHANGE_MODES;
        break;
        
      case 'M':
        ClearModNoAuth(cp);
        changes |= MODECHANGE_MODES;
        break;
      
      case 'T':
        ClearSingleTarg(cp);
        changes |= MODECHANGE_MODES;
        break;

      case 'b':
        clearallbans(cp);
	changes |= MODECHANGE_BANS;
	break;
        
      case 'k':
        /* This is all safe even if there is no key atm */
        freesstring(cp->key);
        cp->key=NULL;
        ClearKey(cp);
	changes |= MODECHANGE_MODES;
        break;
        
      case 'l':
        cp->limit=0;
        ClearLimit(cp);
	changes |= MODECHANGE_MODES;
        break;
    }
  }
   
  if (usermask) {
    /* We have to strip something off each user */
    for (i=0;i<cp->users->hashsize;i++) {
      if (cp->users->content[i]!=nouser && (cp->users->content[i] & usermask)) {
        /* This user exists and has at least one of the modes we're clearing */
        if ((target=getnickbynumeric(cp->users->content[i]))==NULL) {
          /* This really is a fuckup, we found them on the channel but there isn't a user with that numeric */
          /* This means there's a serious bug in the nick/channel tracking code */
          Error("channel",ERR_ERROR,"CLEARMODE failed: user on channel who doesn't exist?");
        } else {
          harg[2]=target;                                  
          /* Yes, these are deliberate three way bitwise ANDs.. */
          if (cp->users->content[i] & usermask & CUMODE_OP)
            triggerhook(HOOK_CHANNEL_DEOPPED, harg);
          if (cp->users->content[i] & usermask & CUMODE_VOICE)
            triggerhook(HOOK_CHANNEL_DEVOICED, harg);          
          cp->users->content[i] &= ~usermask;
        }
      }
    }
  }

  harg[2]=(void *)((long)changes);
  triggerhook(HOOK_CHANNEL_MODECHANGE, harg);
  return CMD_OK;
}
Esempio n. 11
0
int handlemodemsg(void *source, int cargc, char **cargv) {
  channel *cp;
  int dir=1;
  int arg=2;
  char *modestr;
  unsigned long *lp;
  void *harg[4];
  nick *np, *target;
  int hooknum;
  int changes=0;

  if (cargc<2) {
    return CMD_OK;
  }

  if (cargv[0][0]!='#' && cargv[0][0]!='+') {
    /* Not a channel, ignore */
    return CMD_OK;
  }

  if ((cp=findchannel(cargv[0]))==NULL) {
    /* No channel, abort */
    Error("channel",ERR_WARNING,"Mode change on non-existent channel %s",cargv[0]);
    return CMD_OK;
  }
  
  if (((char *)source)[2]=='\0') {
    /* Server mode change, treat as divine intervention */
    np=NULL;
  } else if ((np=getnickbynumericstr((char *)source))==NULL) {
    /* No sender, continue but moan */
    Error("channel",ERR_WARNING,"Mode change by non-existent user %s on channel %s",(char *)source,cp->index->name->content);
  }
  
  /* Set up the hook data */
  harg[0]=cp;
  harg[1]=np;
  harg[3]=(void *)(long)(cp->flags);
  
  /* Process the mode string one character at a time */
  /* Maybe I'll write this more intelligently one day if I can comprehend the ircu code that does this */
  for (modestr=cargv[1];*modestr;modestr++) {
    switch(*modestr) {
      /* Set whether we are adding or removing modes */
      
      case '+': 
        dir=1;
        break;
        
      case '-':
        dir=0;
        break;
      
      /* Simple modes: just set or clear based on value of dir */
      
      case 'n':
        if (dir) { SetNoExtMsg(cp); } else { ClearNoExtMsg(cp); }
	changes |= MODECHANGE_MODES;
        break;
      
      case 't':
        if (dir) { SetTopicLimit(cp); } else { ClearTopicLimit(cp); }
	changes |= MODECHANGE_MODES;
        break;
      
      case 's':
        if (dir) { SetSecret(cp); ClearPrivate(cp); } else { ClearSecret(cp); }
	changes |= MODECHANGE_MODES;
        break;
        
      case 'p':
        if (dir) { SetPrivate(cp); ClearSecret(cp); } else { ClearPrivate(cp); }
	changes |= MODECHANGE_MODES;
        break;
        
      case 'i':
        if (dir) { SetInviteOnly(cp); } else { ClearInviteOnly(cp); }
	changes |= MODECHANGE_MODES;
        break;
        
      case 'm':
        if (dir) { SetModerated(cp); } else { ClearModerated(cp); }
	changes |= MODECHANGE_MODES;
        break;
        
      case 'c':
        if (dir) { SetNoColour(cp); } else { ClearNoColour(cp); }
	changes |= MODECHANGE_MODES;
        break;
        
      case 'C':
        if (dir) { SetNoCTCP(cp); } else { ClearNoCTCP(cp); }
	changes |= MODECHANGE_MODES;
        break;
      
      case 'r':
        if (dir) { SetRegOnly(cp); } else { ClearRegOnly(cp); }
	changes |= MODECHANGE_MODES;
        break;
        
      case 'D':
        if (dir) { SetDelJoins(cp); } else { ClearDelJoins(cp); }
	changes |= MODECHANGE_MODES;
        break;

      case 'u':
        if (dir) { SetNoQuitMsg(cp); } else { ClearNoQuitMsg(cp); }
        changes |= MODECHANGE_MODES;
        break;
      
      case 'N':
        if (dir) { SetNoNotice(cp); } else { ClearNoNotice(cp); }
        changes |= MODECHANGE_MODES;
        break;
        
      case 'M':
        if (dir) { SetModNoAuth(cp); } else { ClearModNoAuth(cp); }
        changes |= MODECHANGE_MODES;
        break;
      
      case 'T':
        if (dir) { SetSingleTarg(cp); } else { ClearSingleTarg(cp); }
        changes |= MODECHANGE_MODES;
        break;
        
      /* Parameter modes: advance parameter and possibly read it in */    
    
      case 'l':
        if (dir) {
          /* +l uses a parameter, but -l does not.
           * If there is no parameter, don't set the mode.
           * I guess we should moan too in that case, but 
           * they might be even nastier to us if we do ;) */
          if (arg<cargc) {
            cp->limit=strtol(cargv[arg++],NULL,10);
            SetLimit(cp);
          }      
        } else {
          ClearLimit(cp);
          cp->limit=0;
        }
	changes |= MODECHANGE_MODES;
        break;
        
      case 'k':
        if (dir) {
          /* +k uses a parameter in both directions */
          if (arg<cargc) {
            freesstring(cp->key); /* It's probably NULL, but be safe */
            cp->key=getsstring(cargv[arg++],KEYLEN);
            SetKey(cp);
          }
        } else {
          freesstring(cp->key);
          cp->key=NULL;
          ClearKey(cp);
          arg++; /* Eat the arg without looking at it, even if it's not there */
        }
	changes |= MODECHANGE_MODES;
        break;
        
      /* Op/Voice */
      
      case 'o':
      case 'v': 
        if (arg<cargc) {
          if((lp=getnumerichandlefromchanhash(cp->users,numerictolong(cargv[arg++],5)))==NULL) {
            /* They're not on the channel; MODE crossed with part/kill/kick/blah */
            Error("channel",ERR_DEBUG,"Mode change for user %s not on channel %s",cargv[arg-1],cp->index->name->content);
          } else { 
            if ((target=getnickbynumeric(*lp))==NULL) {
              /* This really is a fuckup, we found them on the channel but there isn't a user with that numeric */
              /* This means there's a serious bug in the nick/channel tracking code */
              Error("channel",ERR_ERROR,"Mode change for user %s on channel %s who doesn't exist",cargv[arg-1],cp->index->name->content);
            } else { /* Do the mode change whilst admiring the beautiful code layout */
              harg[2]=target;
              if (*modestr=='o') { if (dir) { *lp |= CUMODE_OP;     hooknum=HOOK_CHANNEL_OPPED;    } else 
                                            { *lp &= ~CUMODE_OP;    hooknum=HOOK_CHANNEL_DEOPPED;  } }
                            else { if (dir) { *lp |= CUMODE_VOICE;  hooknum=HOOK_CHANNEL_VOICED;   } else 
                                            { *lp &= ~CUMODE_VOICE; hooknum=HOOK_CHANNEL_DEVOICED; } } 
              triggerhook(hooknum,harg);
            }
          }
        }
	changes |= MODECHANGE_USERS;
        break;
        
      case 'b':
        if (arg<cargc) {
          if (dir) {
            setban(cp,cargv[arg++]);
            triggerhook(HOOK_CHANNEL_BANSET,harg);
          } else {
            clearban(cp,cargv[arg++],0);
            triggerhook(HOOK_CHANNEL_BANCLEAR,harg);
          }
        }
	changes |= MODECHANGE_BANS;
        break;
        
      default:
        Error("channel",ERR_DEBUG,"Unknown mode char '%c' %s on %s",*modestr,dir?"set":"cleared",cp->index->name->content);
        break;
    }
  }

  harg[2]=(void *)((long)changes);
  triggerhook(HOOK_CHANNEL_MODECHANGE,(void *)harg);  
  return CMD_OK;
}