Ejemplo n.º 1
0
bool CIRCNetwork::AddChan(const CString& sName, bool bInConfig) {
	if (sName.empty() || FindChan(sName)) {
		return false;
	}

	CChan* pChan = new CChan(sName, this, bInConfig);
	m_vChans.push_back(pChan);
	return true;
}
Ejemplo n.º 2
0
int
ReloadData()

{
#ifdef NICKSERVICES
  struct NickInfo *temp, *newnick, *nnext;
  int ii;

#ifdef CHANNELSERVICES
  struct ChanInfo *ctemp, *cnext;
#endif

#ifdef MEMOSERVICES
  struct MemoInfo *mtemp, *mnext;
#endif

#endif /* NICKSERVICES */

#ifdef NICKSERVICES

  for (ii = 0; ii < NICKLIST_MAX; ++ii)
    for (temp = nicklist[ii]; temp; temp = temp->next)
      temp->flags |= NS_DELETE;

  if (ns_loaddata() == (-2))
  {
    /*
     * Reload had fatal errors, so use the old database -
     * go through and KEEP all structures marked for deletion
     * and DELETE structures not marked, because they are the
     * ones that were just added in the failed reload
     */

    for (ii = 0; ii < NICKLIST_MAX; ++ii)
    {
      for (temp = nicklist[ii]; temp; temp = nnext)
      {
        nnext = temp->next;

        if (!(temp->flags & NS_DELETE))
          DeleteNick(temp);
        else
        {
          /* remove the deletion flag */
          temp->flags &= ~NS_DELETE;
        }
      }
    }

    return 0;
  }
  else
  {
    /*
     * Reload was ok - now go through and remove the old nick
     * structures marked for deletion
     */

    for (ii = 0; ii < NICKLIST_MAX; ++ii)
    {
      for (temp = nicklist[ii]; temp; temp = nnext)
      {
        nnext = temp->next;

        if (temp->flags & NS_DELETE)
        {
          /*
           * We should try to preserve the old identification
           * data. Before deleting this nickname, attempt
           * to find the corresponding one that was just
           * read from the configuration file, and set it's
           * ident/collide/split_ts variables correctly.
           * It is safe to use FindNick() because it will
           * return the most current entry. If the entry
           * was deleted, FindNick() will return 'temp'
           * so we're still not losing anything.
           */
          if ((newnick = FindNick(temp->nick)))
          {
            newnick->flags |= (temp->flags & NS_IDENTIFIED);
            newnick->collide_ts = temp->collide_ts;

          #ifdef RECORD_SPLIT_TS
            newnick->split_ts = temp->split_ts;
            newnick->whensplit = temp->whensplit;
          #endif /* RECORD_SPLIT_TS */
          }

          DeleteNick(temp);

        } /* if (temp->flags & NS_DELETE) */
      } /* for (temp = nicklist[ii]; temp; temp = nnext) */
    } /* for (ii = 0; ii < NICKLIST_MAX; ++ii) */
  }

#ifdef CHANNELSERVICES

  for (ii = 0; ii < CHANLIST_MAX; ++ii)
    for (ctemp = chanlist[ii]; ctemp; ctemp = ctemp->next)
      ctemp->flags |= CS_DELETE;

  if (cs_loaddata() == (-2))
  {
    /*
     * Reload had fatal errors, so use the old database -
     * go through and KEEP all structures marked for deletion
     * and DELETE structures not marked, because they are the
     * ones that were just added in the failed reload
     */

    for (ii = 0; ii < CHANLIST_MAX; ++ii)
    {
      for (ctemp = chanlist[ii]; ctemp; ctemp = cnext)
      {
        cnext = ctemp->next;

        if (!(ctemp->flags & CS_DELETE))
          DeleteChan(ctemp);
        else
        {
          /* remove the deletion flag */
          ctemp->flags &= ~CS_DELETE;
        }
      }
    }

    return 0;
  }
  else
  {
    struct Channel *cptr;

    /*
     * Reload was ok - now go through and remove the old chan
     * structures marked for deletion
     */

    for (ii = 0; ii < CHANLIST_MAX; ++ii)
    {
      for (ctemp = chanlist[ii]; ctemp; ctemp = cnext)
      {
        cnext = ctemp->next;

        if (ctemp->flags & CS_DELETE)
          DeleteChan(ctemp);
        else
        {
          /*
           * It must be a new channel entry, have ChanServ
           * join the channel
           */
          cptr = FindChannel(ctemp->name);
          if (cptr && !IsChannelMember(cptr, Me.csptr))
            cs_join(ctemp);
        }
      }
    }
    
    /*
     * Now go through the list and have ChanServ part any old chans
     */
    if (Me.csptr)
    {
      struct UserChannel *uc, *ucprev;

      ucprev = NULL;
      for (uc = Me.csptr->firstchan; uc; )
      {
        if (!FindChan(uc->chptr->name))
        {
          if (ucprev)
          {
            ucprev->next = uc->next;
            cs_part(uc->chptr);
            uc = ucprev;
          }
          else
          {
            Me.csptr->firstchan = uc->next;
            cs_part(uc->chptr);
            uc = NULL;
          }
        }

        ucprev = uc;

        if (uc)
          uc = uc->next;
        else
          uc = Me.csptr->firstchan;
      }
    }
  } /* if (Me.csptr) */

#endif /* CHANNELSERVICES */

#ifdef MEMOSERVICES

  for (ii = 0; ii < MEMOLIST_MAX; ++ii)
    for (mtemp = memolist[ii]; mtemp; mtemp = mtemp->next)
      mtemp->flags |= MS_RDELETE;

  if (ms_loaddata() == (-2))
  {
    /*
     * Reload had fatal errors, so use the old database -
     * go through and KEEP all structures marked for deletion
     * and DELETE structures not marked, because they are the
     * ones that were just added in the failed reload
     */

    for (ii = 0; ii < MEMOLIST_MAX; ++ii)
    {
      for (mtemp = memolist[ii]; mtemp; mtemp = mnext)
      {
        mnext = mtemp->next;

        if (!(mtemp->flags & MS_RDELETE))
          DeleteMemoList(mtemp);
        else
        {
          /* remove the deletion flag */
          mtemp->flags &= ~MS_RDELETE;
        }
      }
    }

    return 0;
  }
  else
  {
    /*
     * Reload was ok - now go through and remove the old memo
     * structures marked for deletion
     */

    for (ii = 0; ii < MEMOLIST_MAX; ++ii)
    {
      for (mtemp = memolist[ii]; mtemp; mtemp = mnext)
      {
        mnext = mtemp->next;

        if (mtemp->flags & MS_RDELETE)
          DeleteMemoList(mtemp);
      }
    }
  }

#endif /* MEMOSERVICES */

#endif /* NICKSERVICES */

#ifdef STATSERVICES

  if (ss_loaddata() == (-2))
    return 0;

#endif /* STATSERVICES */

#ifdef SEENSERVICES

  if (es_loaddata() == (-2))
    return 0;

#endif /* SEENSERVICES */

  if (os_loaddata() == (-2))
    return 0;

  return 1;
} /* ReloadData() */
Ejemplo n.º 3
0
void CIRCNetwork::Clone(const CIRCNetwork& Network) {
	m_sName = Network.GetName();

	SetNick(Network.GetNick());
	SetAltNick(Network.GetAltNick());
	SetIdent(Network.GetIdent());
	SetRealName(Network.GetRealName());

	// Servers
	const vector<CServer*>& vServers = Network.GetServers();
	CString sServer;
	CServer* pCurServ = GetCurrentServer();

	if (pCurServ) {
		sServer = pCurServ->GetName();
	}

	DelServers();

	unsigned int a;
	for (a = 0; a < vServers.size(); a++) {
		CServer* pServer = vServers[a];
		AddServer(pServer->GetName(), pServer->GetPort(), pServer->GetPass(), pServer->IsSSL());
	}

	m_uServerIdx = 0;
	for (a = 0; a < m_vServers.size(); a++) {
		if (sServer.Equals(m_vServers[a]->GetName())) {
			m_uServerIdx = a + 1;
			break;
		}
	}
	if (m_uServerIdx == 0) {
		m_uServerIdx = m_vServers.size();
		CIRCSock* pSock = GetIRCSock();

		if (pSock) {
			PutStatus("Jumping servers because this server is no longer in the list");
			pSock->Quit();
		}
	}
	// !Servers

	// Chans
	const vector<CChan*>& vChans = Network.GetChans();
	for (a = 0; a < vChans.size(); a++) {
		CChan* pNewChan = vChans[a];
		CChan* pChan = FindChan(pNewChan->GetName());

		if (pChan) {
			pChan->SetInConfig(pNewChan->InConfig());
		} else {
			AddChan(pNewChan->GetName(), pNewChan->InConfig());
		}
	}

	for (a = 0; a < m_vChans.size(); a++) {
		CChan* pChan = m_vChans[a];
		CChan* pNewChan = Network.FindChan(pChan->GetName());

		if (!pNewChan) {
			pChan->SetInConfig(false);
		} else {
			pChan->Clone(*pNewChan);
		}
	}
	// !Chans

	// Modules
	set<CString> ssUnloadMods;
	CModules& vCurMods = GetModules();
	const CModules& vNewMods = Network.GetModules();

	for (a = 0; a < vNewMods.size(); a++) {
		CString sModRet;
		CModule* pNewMod = vNewMods[a];
		CModule* pCurMod = vCurMods.FindModule(pNewMod->GetModName());

		if (!pCurMod) {
			vCurMods.LoadModule(pNewMod->GetModName(), pNewMod->GetArgs(), CModInfo::NetworkModule, m_pUser, this, sModRet);
		} else if (pNewMod->GetArgs() != pCurMod->GetArgs()) {
			vCurMods.ReloadModule(pNewMod->GetModName(), pNewMod->GetArgs(), m_pUser, this, sModRet);
		}
	}

	for (a = 0; a < vCurMods.size(); a++) {
		CModule* pCurMod = vCurMods[a];
		CModule* pNewMod = vNewMods.FindModule(pCurMod->GetModName());

		if (!pNewMod) {
			ssUnloadMods.insert(pCurMod->GetModName());
		}
	}

	for (set<CString>::iterator it = ssUnloadMods.begin(); it != ssUnloadMods.end(); ++it) {
		vCurMods.UnloadModule(*it);
	}
	// !Modules

	SetIRCConnectEnabled(Network.GetIRCConnectEnabled());
}
Ejemplo n.º 4
0
static void
m_list(struct Luser *lptr, struct NickInfo *nptr, int ac, char **av)

{
  struct MemoInfo *mi = NULL;
  struct Memo *memoptr;
  char status[4];

  if (!nptr)
    return;

  if (ac >= 2)
  {
    if (av[1][0] == '#')
    {
    #ifdef CHANNELSERVICES
      struct ChanInfo *ci;
    #endif

    #ifndef CHANNELSERVICES
      notice(n_MemoServ, lptr->nick,
        "Channel services are disabled");
      return;
    #else
      if (!(ci = FindChan(av[1])))
      {
        notice(n_MemoServ, lptr->nick,
          ERR_CH_NOT_REGGED,
          av[1]);
        return;
      }

      if (!HasAccess(ci, lptr, CA_AUTOOP))
      {
        notice(n_MemoServ, lptr->nick,
          "AutoOp access is required to list memos for [\002%s\002]",
          ci->name);
        return;
      }

      mi = FindMemoList(ci->name);
      if (!mi)
      {
        notice(n_MemoServ, lptr->nick,
          "There are no recorded memos for [\002%s\002]",
          ci->name);
        return;
      }
    #endif /* CHANNELSERVICES */

    }
  }

  if (!mi)
  {
    if (!(mi = FindMemoList(nptr->nick)))
    {
      notice(n_MemoServ, lptr->nick,
        "You have no recorded memos");
      return;
    }
  }

  notice(n_MemoServ, lptr->nick,
    "-- Listing memos for [\002%s\002] --",
    mi->name);
  notice(n_MemoServ, lptr->nick,
    "    Idx Sender             Time Sent");
  for (memoptr = mi->memos; memoptr; memoptr = memoptr->next)
  {
    if (memoptr->flags & MS_DELETE)
      strcpy(status, "(D)");
    else if (mi->name[0] != '#')
    {
      if (memoptr->flags & MS_READ)
        strcpy(status, "(R)");
      else
        strcpy(status, "(N)");
    }
    else
      status[0] = '\0';

    notice(n_MemoServ, lptr->nick,
      "%3s %-3d %-18s %s ago",
      status,
      memoptr->index,
      memoptr->sender,
      timeago(memoptr->sent, 1));
  }
  notice(n_MemoServ, lptr->nick,
    "-- End of list --");
} /* m_list() */
Ejemplo n.º 5
0
bool CUser::Clone(const CUser& User, CString& sErrorRet, bool bCloneChans) {
	unsigned int a = 0;
	sErrorRet.clear();

	if (!User.IsValid(sErrorRet, true)) {
		return false;
	}

	// user names can only specified for the constructor, changing it later
	// on breaks too much stuff (e.g. lots of paths depend on the user name)
	if (GetUserName() != User.GetUserName()) {
		DEBUG("Ignoring username in CUser::Clone(), old username [" << GetUserName()
				<< "]; New username [" << User.GetUserName() << "]");
	}

	if (!User.GetPass().empty()) {
		SetPass(User.GetPass(), User.GetPassHashType(), User.GetPassSalt());
	}

	SetNick(User.GetNick(false));
	SetAltNick(User.GetAltNick(false));
	SetIdent(User.GetIdent(false));
	SetRealName(User.GetRealName());
	SetStatusPrefix(User.GetStatusPrefix());
	SetBindHost(User.GetBindHost());
	SetDCCBindHost(User.GetDCCBindHost());
	SetQuitMsg(User.GetQuitMsg());
	SetSkinName(User.GetSkinName());
	SetDefaultChanModes(User.GetDefaultChanModes());
	SetBufferCount(User.GetBufferCount(), true);
	SetJoinTries(User.JoinTries());
	SetMaxJoins(User.MaxJoins());

	// Allowed Hosts
	m_ssAllowedHosts.clear();
	const set<CString>& ssHosts = User.GetAllowedHosts();
	for (set<CString>::const_iterator it = ssHosts.begin(); it != ssHosts.end(); ++it) {
		AddAllowedHost(*it);
	}

	for (a = 0; a < m_vClients.size(); a++) {
		CClient* pSock = m_vClients[a];

		if (!IsHostAllowed(pSock->GetRemoteIP())) {
			pSock->PutStatusNotice("You are being disconnected because your IP is no longer allowed to connect to this user");
			pSock->Close();
		}
	}

	// !Allowed Hosts

	// Servers
	const vector<CServer*>& vServers = User.GetServers();
	CString sServer;
	CServer* pCurServ = GetCurrentServer();

	if (pCurServ) {
		sServer = pCurServ->GetName();
	}

	DelServers();

	for (a = 0; a < vServers.size(); a++) {
		CServer* pServer = vServers[a];
		AddServer(pServer->GetName(), pServer->GetPort(), pServer->GetPass(), pServer->IsSSL());
	}

	m_uServerIdx = 0;
	for (a = 0; a < m_vServers.size(); a++) {
		if (sServer.Equals(m_vServers[a]->GetName())) {
			m_uServerIdx = a + 1;
			break;
		}
	}
	if (m_uServerIdx == 0) {
		m_uServerIdx = m_vServers.size();
		CIRCSock* pSock = GetIRCSock();

		if (pSock) {
			PutStatus("Jumping servers because this server is no longer in the list");
			pSock->Quit();
		}
	}
	// !Servers

	// Chans
	const vector<CChan*>& vChans = User.GetChans();
	for (a = 0; a < vChans.size(); a++) {
		CChan* pNewChan = vChans[a];
		CChan* pChan = FindChan(pNewChan->GetName());

		if (pChan) {
			pChan->SetInConfig(pNewChan->InConfig());
		} else {
			AddChan(pNewChan->GetName(), pNewChan->InConfig());
		}
	}

	for (a = 0; a < m_vChans.size(); a++) {
		CChan* pChan = m_vChans[a];
		CChan* pNewChan = User.FindChan(pChan->GetName());

		if (!pNewChan) {
			pChan->SetInConfig(false);
		} else {
			if (bCloneChans)
				pChan->Clone(*pNewChan);
		}
	}
	// !Chans

	// CTCP Replies
	m_mssCTCPReplies.clear();
	const MCString& msReplies = User.GetCTCPReplies();
	for (MCString::const_iterator it = msReplies.begin(); it != msReplies.end(); ++it) {
		AddCTCPReply(it->first, it->second);
	}
	// !CTCP Replies

	// Flags
	SetIRCConnectEnabled(User.GetIRCConnectEnabled());
	SetKeepBuffer(User.KeepBuffer());
	SetMultiClients(User.MultiClients());
	SetBounceDCCs(User.BounceDCCs());
	SetUseClientIP(User.UseClientIP());
	SetDenyLoadMod(User.DenyLoadMod());
	SetAdmin(User.IsAdmin());
	SetDenySetBindHost(User.DenySetBindHost());
	SetTimestampAppend(User.GetTimestampAppend());
	SetTimestampPrepend(User.GetTimestampPrepend());
	SetTimestampFormat(User.GetTimestampFormat());
	SetTimezoneOffset(User.GetTimezoneOffset());
	// !Flags

	// Modules
	set<CString> ssUnloadMods;
	CModules& vCurMods = GetModules();
	const CModules& vNewMods = User.GetModules();

	for (a = 0; a < vNewMods.size(); a++) {
		CString sModRet;
		CModule* pNewMod = vNewMods[a];
		CModule* pCurMod = vCurMods.FindModule(pNewMod->GetModName());

		if (!pCurMod) {
			vCurMods.LoadModule(pNewMod->GetModName(), pNewMod->GetArgs(), this, sModRet);
		} else if (pNewMod->GetArgs() != pCurMod->GetArgs()) {
			vCurMods.ReloadModule(pNewMod->GetModName(), pNewMod->GetArgs(), this, sModRet);
		}
	}

	for (a = 0; a < vCurMods.size(); a++) {
		CModule* pCurMod = vCurMods[a];
		CModule* pNewMod = vNewMods.FindModule(pCurMod->GetModName());

		if (!pNewMod) {
			ssUnloadMods.insert(pCurMod->GetModName());
		}
	}

	for (set<CString>::iterator it = ssUnloadMods.begin(); it != ssUnloadMods.end(); ++it) {
		vCurMods.UnloadModule(*it);
	}
	// !Modules

	return true;
}
Ejemplo n.º 6
0
static void
m_purge(struct Luser *lptr, struct NickInfo *nptr, int ac, char **av)

{
  struct MemoInfo *mi;
  int cnt;

  if (!nptr)
    return;

  if (ac >= 2)
  {
    #ifdef CHANNELSERVICES
      struct ChanInfo *ci;
    #endif

    #ifndef CHANNELSERVICES

      notice(n_MemoServ, lptr->nick,
        "Channel services are disabled");
      return;

    #else

      if (!(ci = FindChan(av[1])))
      {
        notice(n_MemoServ, lptr->nick,
          ERR_CH_NOT_REGGED,
          av[1]);
        return;
      }

      if (!HasAccess(ci, lptr, CA_SUPEROP))
      {
        notice(n_MemoServ, lptr->nick,
          "SuperOp access is required to purge memos for [\002%s\002]",
          ci->name);
        return;
      }

      if (!(mi = FindMemoList(ci->name)))
      {
        notice(n_MemoServ, lptr->nick,
          "There are no recorded memos for [\002%s\002]",
          ci->name);
        return;
      }

      cnt = PurgeMemos(mi);

      notice(n_MemoServ, lptr->nick,
        "Memos marked for deletion on [\002%s\002] have been purged (%d found)",
        ci->name,
        cnt);

      return;

    #endif /* CHANNELSERVICES */
  }
  else if (!(mi = FindMemoList(nptr->nick)))
  {
    notice(n_MemoServ, lptr->nick,
      "You have no recorded memos");
    return;
  }

  cnt = PurgeMemos(mi);

  notice(n_MemoServ, lptr->nick,
    "Your memos marked for deletion have been purged (%d found)",
    cnt);
} /* m_purge() */
Ejemplo n.º 7
0
static void
m_send(struct Luser *lptr, struct NickInfo *nptr, int ac, char **av)

{
  char *memotext, /* memo text */
       *to; /* who the memo is sent to */
  int  index;
  struct NickInfo *master = NULL,
                  *realptr = NULL;
#ifdef CHANNELSERVICES
  struct ChanInfo *ci = NULL;
#endif

  if (ac < 3)
  {
    notice(n_MemoServ, lptr->nick,
      "Syntax: SEND <nick/channel> <text>");
    notice(n_MemoServ, lptr->nick,
      ERR_MORE_INFO,
      n_MemoServ,
      "SEND");
    return;
  }

  if (*av[1] == '#')
  {
    #ifndef CHANNELSERVICES

      notice(n_MemoServ, lptr->nick,
        "Channel services are disabled");
      return;

    #else

      if (!(ci = FindChan(av[1])))
      {
        notice(n_MemoServ, lptr->nick,
          ERR_CH_NOT_REGGED,
          av[1]);
        return;
      }

      if (!HasAccess(ci, lptr, CA_AUTOOP))
      {
        notice(n_MemoServ, lptr->nick,
          "AutoOp access is required to send a memo to [\002%s\002]",
          ci->name);
        return;
      }

      to = ci->name;

    #endif /* CHANNELSERVICES */
  }
  else
  {
    /* it was sent to a nickname */

    if (!(realptr = FindNick(av[1])))
    {
      notice(n_MemoServ, lptr->nick,
        ERR_NOT_REGGED,
        av[1]);
      return;
    }

    master = GetMaster(realptr);
    assert(master != 0);

    if (!(master->flags & NS_MEMOS))
    {
      notice(n_MemoServ, lptr->nick,
        "[\002%s\002] is rejecting all memos",
        av[1]);
      return;
    }

    to = master->nick;
  }

  /* get the actual memo text now */
  if (ac < 3)
    memotext = MyStrdup("");
  else
    memotext = GetString(ac - 2, av + 2);

  index = StoreMemo(to, memotext, lptr);

  if (index)
  {
    notice(n_MemoServ, lptr->nick,
      "Memo has been recorded for [\002%s\002]",
      realptr ? realptr->nick : to);

    if (realptr && master)
    {
      /*
       * It was sent to a nickname - check if they are online
       * and identified and optionally notify them
       *
       * we should have here linklist traversal and notifying all clients.
       * however, that could be a bit cpu intensitive to do for every
       * memo, so i haven't done it so far. -kre
       */
      if ((master->flags & NS_MEMONOTIFY) &&
          (realptr->flags & NS_IDENTIFIED) &&
          FindClient(realptr->nick))
      {
        notice(n_MemoServ, realptr->nick,
          "You have a new memo from \002%s\002 (#%d)",
          lptr->nick,
          index);
        notice(n_MemoServ, realptr->nick,
          "Type \002/msg %s READ %d\002 to read it",
          n_MemoServ,
          index);
      }
    } /* if (ni) */
  #ifdef CHANNELSERVICES
    else
    {
      struct Channel *chptr;
      struct ChanAccess *ca;
      char *newtext;

      /*
       * It was sent to a channel - notify every AOP or higher
       */
      if ((ci) && (chptr = FindChannel(to)))
      {
        struct ChannelUser *cu;
        struct NickInfo *tmpn;

        for (cu = chptr->firstuser; cu; cu = cu->next)
        {
          if (FindService(cu->lptr))
            continue;

          tmpn = GetLink(cu->lptr->nick);

          if (HasAccess(ci, cu->lptr, CA_AUTOOP))
          {
            if (tmpn)
            {
              /* don't notify people who don't want memos */
              if (!(tmpn->flags & NS_MEMOS) ||
                  !(tmpn->flags & NS_MEMONOTIFY))
                continue;
            }

            notice(n_MemoServ, cu->lptr->nick,
              "New channel memo from \002%s\002 (#%d)",
              lptr->nick,
              index);
            notice(n_MemoServ, cu->lptr->nick,
              "Type \002/msg %s READ %s %d\002 to read it",
              n_MemoServ,
              chptr->name,
              index);
          }
        }
      }

      newtext = (char *) MyMalloc(strlen(memotext) + strlen(ci->name) + 4);
      ircsprintf(newtext, "(%s) %s", ci->name, memotext);
      for (ca = ci->access; ca; ca = ca->next)
      {
        if (ca->nptr)
          StoreMemo(ca->nptr->nick, newtext, lptr);
      }

      MyFree(newtext);

    } /* else */
  #endif /* CHANNELSERVICES */
  } /* if (index) */

  MyFree (memotext);
} /* m_send() */
Ejemplo n.º 8
0
static void
m_forward(struct Luser *lptr, struct NickInfo *nptr, int ac, char **av)

{
  struct MemoInfo *from, *target;
  struct Memo *memoptr = NULL;
  struct Memo *fromptr;
  char *to; /* who the memo is sent to */
  int index, cnt;
  char buf[MAXLINE];
  struct NickInfo *master,
                  *realptr;
#ifdef CHANNELSERVICES
  struct ChanInfo *ci = NULL;
#endif

  if (!nptr)
    return;

  if (ac < 3)
  {
    notice(n_MemoServ, lptr->nick,
      "Syntax: FORWARD <index|ALL> <nick/channel>");
    notice(n_MemoServ, lptr->nick,
      ERR_MORE_INFO,
      n_MemoServ,
      "FORWARD");
    return;
  }

  if (!(from = FindMemoList(nptr->nick)))
  {
    notice(n_MemoServ, lptr->nick,
      "You have no recorded memos");
    return;
  }

  index = IsNum(av[1]);
  if ((index < 0) || (index > from->memocnt) || 
      (!index && (irccmp(av[1], "ALL") != 0)))
  {
    notice(n_MemoServ, lptr->nick,
      "[\002%s\002] is an invalid index",
      av[1]);
    return;
  }

  master = realptr = NULL;

  if (*av[2] == '#')
  {
    #ifndef CHANNELSERVICES
      notice(n_MemoServ, lptr->nick,
        "Channel services are disabled");
      return;
    #else
      if (!(ci = FindChan(av[2])))
      {
        notice(n_MemoServ, lptr->nick,
          ERR_CH_NOT_REGGED,
          av[2]);
        return;
      }

      if (!HasAccess(ci, lptr, CA_AUTOOP))
      {
        notice(n_MemoServ, lptr->nick,
          "AutoOp access is required to forward a memo to [\002%s\002]",
          ci->name);
        return;
      }

      to = ci->name;

    #endif
  }
  else
  {
    /* it was sent to a nickname */

    if (!(realptr = FindNick(av[2])))
    {
      notice(n_MemoServ, lptr->nick,
        ERR_NOT_REGGED,
        av[2]);
      return;
    }

    master = GetMaster(realptr);
    assert(master != 0);

    if (!(master->flags & NS_MEMOS))
    {
      notice(n_MemoServ, lptr->nick,
        "[\002%s\002] is rejecting all memos",
        realptr->nick);
      return;
    }

    to = master->nick;
  }

  if (!(target = FindMemoList(to)))
  {
    target = MakeMemoList();
    target->name = MyStrdup(to);
    AddMemoList(target);
  }
  else if (from == target)
  {
    /*
     * If we let someone forward memos to themselves,
     * the below loop will never end, eventually malloc()'ing too
     * much and crashing - head it off at the pass
     */
    notice(n_MemoServ, lptr->nick,
      "You cannot forward memos to yourself");
    return;
  }

  if (MaxMemos && (target->memocnt >= MaxMemos))
  {
    notice(n_MemoServ, lptr->nick,
      "%s has reached the maximum memo limit, and cannot receive more",
      to);
    return;
  }

  cnt = 0;
  for (fromptr = from->memos; fromptr; fromptr = fromptr->next)
  {
    if (!index || (fromptr->index == index))
    {
      memset(&buf, 0, MAXLINE);

      target->memocnt++;
      target->newmemos++;
      cnt++;

      memoptr = MakeMemo();
      memoptr->sender = MyStrdup(lptr->nick);
      memoptr->sent = current_ts;
      memoptr->index = target->memocnt;

      strcpy(buf, "[Fwd]: ");
      strncat(buf, fromptr->text, MAXLINE - 8);
      memoptr->text = MyStrdup(buf);

      AddMemo(target, memoptr);

      if (MaxMemos && (target->memocnt >= MaxMemos))
        break;
    }
  }

  if (!index)
    ircsprintf(buf, "All memos have");
  else
    ircsprintf(buf, "Memo #%d has", index);

  notice(n_MemoServ, lptr->nick,
    "%s been forwarded to [\002%s\002]",
    buf,
    target->name);

  if (master && realptr)
  {
    /*
     * It was sent to a nickname - check if they are online
     * and notify them
     */
    if ((master->flags & NS_MEMONOTIFY) && 
        (realptr->flags & NS_IDENTIFIED) &&
        FindClient(realptr->nick))
    {
      notice(n_MemoServ, realptr->nick,
        "You have %d new forwarded memo%s from \002%s\002",
        cnt,
        (cnt == 1) ? "" : "s",
        memoptr->sender);
      notice(n_MemoServ, realptr->nick,
        "Type \002/msg %s LIST\002 to view %s",
        n_MemoServ,
        (cnt == 1) ? "it" : "them");
    }
  } /* if (master && realptr) */
#ifdef CHANNELSERVICES
  else
  {
    struct Channel *chptr;

    /*
     * It was sent to a channel - notify every AOP or higher
     */
    if ((ci) && (chptr = FindChannel(target->name)))
    {
      struct ChannelUser *cu;
      struct NickInfo *tmpn;

      for (cu = chptr->firstuser; cu; cu = cu->next)
      {
        if (FindService(cu->lptr))
          continue;

        tmpn = GetLink(cu->lptr->nick);

        if (HasAccess(ci, cu->lptr, CA_AUTOOP))
        {
          if (tmpn)
          {
            if (!(tmpn->flags & NS_MEMOS) ||
                !(tmpn->flags & NS_MEMONOTIFY))
              continue;
          }

          notice(n_MemoServ, cu->lptr->nick,
            "%d new forwarded channel memo%s from \002%s\002",
            cnt,
            (cnt == 1) ? "" : "s",
            memoptr->sender);

          notice(n_MemoServ, cu->lptr->nick,
            "Type \002/msg %s LIST %s\002 to view %s",
            n_MemoServ,
            chptr->name,
            (cnt == 1) ? "it" : "them");
        }
      }
    }
  } /* else */
#endif /* CHANNELSERVICES */
} /* m_forward() */
Ejemplo n.º 9
0
static void
m_undel(struct Luser *lptr, struct NickInfo *nptr, int ac, char **av)

{
  struct MemoInfo *mi;
  struct Memo *memoptr;
  char istr[MAXLINE];
  int index;

  if (!nptr)
    return;

  if (ac < 2)
  {
    notice(n_MemoServ, lptr->nick,
      "Syntax: UNDEL [channel] <index|all>");
    notice(n_MemoServ, lptr->nick,
      ERR_MORE_INFO,
      n_MemoServ,
      "UNDEL");
    return;
  }

  if (ac >= 3)
  {
    #ifdef CHANNELSERVICES
      struct ChanInfo *ci;
    #endif

    #ifndef CHANNELSERVICES
      notice(n_MemoServ, lptr->nick,
        "Channel services are disabled");
      return;
    #else
      if (!(ci = FindChan(av[1])))
      {
        notice(n_MemoServ, lptr->nick,
          ERR_CH_NOT_REGGED,
          av[1]);
        return;
      }

      if (!HasAccess(ci, lptr, CA_SUPEROP))
      {
        notice(n_MemoServ, lptr->nick,
          "SuperOp access is required to undelete memos for [\002%s\002]",
          ci->name);
        return;
      }

      if (!(mi = FindMemoList(ci->name)))
      {
        notice(n_MemoServ, lptr->nick,
          "There are no recorded memos for [\002%s\002]",
          ci->name);
        return;
      }
      index = IsNum(av[2]);
    #endif /* CHANNELSERVICES */

  }
  else
  {
    if (!(mi = FindMemoList(nptr->nick)))
    {
      notice(n_MemoServ, lptr->nick,
        "You have no recorded memos");
      return;
    }
    index = IsNum(av[1]);
  }

  if ((index < 0) || (index > mi->memocnt) || 
      (!index && (irccmp(av[(ac >= 3) ? 2 : 1], "ALL") != 0)))
  {
    notice(n_MemoServ, lptr->nick,
      "[\002%s\002] is an invalid index",
      av[(ac >= 3) ? 2 : 1]);
    return;
  }

  for (memoptr = mi->memos; memoptr; memoptr = memoptr->next)
  {
    if (!index || (memoptr->index == index))
      memoptr->flags &= ~MS_DELETE;
  }

  if (index)
    ircsprintf(istr, "Memo #%d has", index);
  else
    strcpy(istr, "All memos have");

  if (ac >= 3)
    notice(n_MemoServ, lptr->nick,
      "%s been unmarked for deletion for [\002%s\002]",
      istr,
      av[1]);
  else
    notice(n_MemoServ, lptr->nick,
      "%s been unmarked for deletion",
      istr);
} /* m_undel() */
Ejemplo n.º 10
0
static void
m_read(struct Luser *lptr, struct NickInfo *nptr, int ac, char **av)

{
  struct MemoInfo *mi;
  int index;
  struct Memo *memoptr;
  char istr[10];

  if (!nptr)
    return;

  if (ac < 2)
  {
    notice(n_MemoServ, lptr->nick,
      "Syntax: READ [channel] <index|all>");
    notice(n_MemoServ, lptr->nick,
      ERR_MORE_INFO,
      n_MemoServ,
      "READ");
    return;
  }

  if (ac >= 3)
  {
    #ifdef CHANNELSERVICES
      struct ChanInfo *ci;
    #endif

    #ifndef CHANNELSERVICES
      notice(n_MemoServ, lptr->nick,
        "Channel services are disabled");
      return;
    #else
      if (!(ci = FindChan(av[1])))
      {
        notice(n_MemoServ, lptr->nick,
          ERR_CH_NOT_REGGED,
          av[1]);
        return;
      }

      if (!HasAccess(ci, lptr, CA_AUTOOP))
      {
        notice(n_MemoServ, lptr->nick,
          "AutoOp access is required to read memos for [\002%s\002]",
          ci->name);
        return;
      }

      if (!(mi = FindMemoList(ci->name)))
      {
        notice(n_MemoServ, lptr->nick,
          "There are no recorded memos for [\002%s\002]",
          ci->name);
        return;
      }
      index = IsNum(av[2]);

    #endif /* CHANNELSERVICES */
  }
  else
  {
    if (!(mi = FindMemoList(nptr->nick)))
    {
      notice(n_MemoServ, lptr->nick,
        "You have no recorded memos");
      return;
    }
    index = IsNum(av[1]);
  }

  if ((index < 0) || (index > mi->memocnt) || 
      (!index && (irccmp(av[(ac >= 3) ? 2 : 1], "ALL") != 0)))
  {
    notice(n_MemoServ, lptr->nick,
      "[\002%s\002] is an invalid index",
      av[(ac >= 3) ? 2 : 1]);
    return;
  }

  for (memoptr = mi->memos; memoptr; memoptr = memoptr->next)
  {
    if (!index || (memoptr->index == index))
    {
      notice(n_MemoServ, lptr->nick,
        "Memo #%d from %s (sent %s ago):",
        memoptr->index,
        memoptr->sender,
        timeago(memoptr->sent, 1));
      notice(n_MemoServ, lptr->nick,
        memoptr->text);
      if (ac < 3)
      {
        /* only mark nickname memos as read - not channel memos */
        if (!(memoptr->flags & MS_READ))
          mi->newmemos--;
        memoptr->flags |= MS_READ;
      }
    }
  }

  if (index)
    ircsprintf(istr, "%d", index);
  else
    strcpy(istr, "ALL");

  if (ac >= 3)
    notice(n_MemoServ, lptr->nick,
      "To delete, type \002/msg %s DEL %s %s",
      n_MemoServ,
      av[1],
      istr);
  else
    notice(n_MemoServ, lptr->nick,
      "To delete, type \002/msg %s DEL %s",
      n_MemoServ,
      istr);
    
} /* m_read() */
Ejemplo n.º 11
0
void
UpdateChanModes(struct Luser *lptr, char *who, struct Channel *cptr,
                char *modes)

{
  int add;
  char *tmp, *p;
  register char ch;
  struct Luser *userptr;
#if defined(NICKSERVICES) && defined(CHANNELSERVICES)
  int cs_deoped = 0; /* was chanserv deoped? */
#endif

  char **modeargs; /* arguements to +l/k/o/v modes */
  char tempargs[MAXLINE];
  int argcnt; /* number of arguements */
  int argidx; /* current index in modeargs[] */

#ifndef SAVE_TS
  char sendstr[MAXLINE];
#endif

  if (!cptr)
    return;

  assert(lptr || who);

  if (lptr)
  {
    SendUmode(OPERUMODE_M,
      "*** %s: Mode [%s] by %s!%s@%s",
      cptr->name,
      modes,
      lptr->nick,
      lptr->username,
      lptr->hostname);

    putlog(LOG3,
      "%s: mode change \"%s\" by %s!%s@%s",
      cptr->name,
      modes,
      lptr->nick,
      lptr->username,
      lptr->hostname);
  }
  else
  {
    SendUmode(OPERUMODE_M,
      "*** %s: Mode [%s] by %s",
      cptr->name,
      modes,
      who);

    putlog(LOG3,
      "%s: mode change \"%s\" by %s",
      cptr->name,
      modes,
      who);
  }

  if ((tmp = strchr(modes, ' ')))
    strcpy(tempargs, *(tmp + 1) ? tmp + 1 : "");
  else
    tempargs[0] = '\0';

  argcnt = SplitBuf(tempargs, &modeargs);

  /*
   * This routine parses the given channel modes and keeps
   * the corresponding lists correctly updated - also make
   * sure OperServ and ChanServ remain opped
   */

  add = 0;
  argidx = (-1);

  for (tmp = modes; *tmp; ++tmp)
  {
    ch = *tmp;

    if (IsSpace(ch))
      break;

    switch (ch)
    {
      case ' ':
      case '\n':
      case '\r': break;

      case '-':
      {
        add = 0;
        break;
      }
      case '+':
      {
        add = 1;
        break;
      }

      /*
       * Op/DeOp
       */
      case 'o':
      {
        ++argidx;
        if (argidx >= argcnt)
        {
          /*
           * there are more 'o' flags than there are nicknames,
           * just break
           */
          break;
        }

        if (!(userptr = FindClient(modeargs[argidx])))
          break;

        SetChannelMode(cptr, add, MODE_O, userptr, 0);

        if (add)
        {
        #ifdef STATSERVICES
          if (lptr)
            ++lptr->numops;
        #endif
        } /* if (add) */
        else
        {
          if (userptr == Me.osptr)
          {
            if (!FloodCheck(cptr, lptr, Me.osptr, 0))
            {
	      #ifdef SAVE_TS
                os_part(cptr);
                os_join(cptr);
	      #else
                toserv(":%s MODE %s +o %s\n",
                  n_OperServ,
                  cptr->name,
                  n_OperServ);
	      #endif
            }

            if (!lptr)
            {
              putlog(LOG1, "%s: %s attempted to deop %s",
                cptr->name,
                who,
                n_OperServ);
            }
            else
            {
              putlog(LOG1, "%s: %s!%s@%s attempted to deop %s",
                cptr->name,
                lptr->nick,
                lptr->username,
                lptr->hostname,
                n_OperServ);
            }
          }
        #if defined(NICKSERVICES) && defined(CHANNELSERVICES)
          else if (userptr == Me.csptr)
          {
            cs_deoped = 1;
          }
        #endif /* defined(NICKSERVICES) && defined(CHANNELSERVICES) */

        #ifdef STATSERVICES
          if (lptr)
            ++lptr->numdops;
        #endif
        } /* else if (!add) */

        #if defined(NICKSERVICES) && defined(CHANNELSERVICES)
          cs_CheckModes(lptr,
            FindChan(cptr->name),
            !add,
            MODE_O,
            userptr);
        #endif

        break;
      } /* case 'o' */

      /*
       * Voice/DeVoice
       */
      case 'v':
      {
        ++argidx;
        if (argidx >= argcnt)
          break;

        if (!(userptr = FindClient(modeargs[argidx])))
          break;

        SetChannelMode(cptr, add, MODE_V, userptr, 0);

        if (add)
        {
        #ifdef STATSERVICES
          if (lptr)
            ++lptr->numvoices;
        #endif
        }
        else
        {
        #ifdef STATSERVICES
          if (lptr)
            ++lptr->numdvoices;
        #endif
        } /* else if (!add) */

      #if defined(NICKSERVICES) && defined(CHANNELSERVICES)
        cs_CheckModes(lptr,
          FindChan(cptr->name),
          !add,
          MODE_V,
          userptr);
      #endif

        break;
      } /* case 'v' */

#ifdef HYBRID7
      /* HalfOp/DeHalfOp -Janos */
      case 'h':
      {
        ++argidx;
        if (argidx >= argcnt)
          break;

        if (!(userptr = FindClient(modeargs[argidx])))
          break;

        SetChannelMode(cptr, add, MODE_H, userptr, 0);

        if (add)
        {
#ifdef STATSERVICES
          if (lptr)
            ++lptr->numhops;
#endif
        }
        else
        {
#ifdef STATSERVICES
          if (lptr)
            ++lptr->numdhops;
#endif
        } /* else if (!add) */

#if defined(NICKSERVICES) && defined(CHANNELSERVICES)
        cs_CheckModes(lptr, FindChan(cptr->name), !add, MODE_H, userptr);
#endif
        break;
      } /* case 'h'*/
#endif /* HYBRID7 */

      /*
       * Channel limit
       */
      case 'l':
      {
        if (add)
        {
          ++argidx;
          if (argidx >= argcnt)
            break;

          cptr->limit = atoi(modeargs[argidx]);
        }
        else
          cptr->limit = 0;

      #if defined(NICKSERVICES) && defined(CHANNELSERVICES)
        cs_CheckModes(lptr,
          FindChan(cptr->name),
          !add,
          MODE_L,
          0);
      #endif

        break;
      } /* case 'l' */

      /*
       * Channel key
       */
      case 'k':
      {
        ++argidx;
        if (argidx >= argcnt)
          break;

      #ifndef BLOCK_ALLOCATION
        if (cptr->key)
          MyFree(cptr->key);
      #endif

        if (add)
        {
        #ifdef BLOCK_ALLOCATION
          strncpy(cptr->key, modeargs[argidx], KEYLEN);
          cptr->key[KEYLEN] = '\0';
        #else
          cptr->key = MyStrdup(modeargs[argidx]);
        #endif /* BLOCK_ALLOCATION */
        }
        else
        {
        #ifdef BLOCK_ALLOCATION
          cptr->key[0] = '\0';
        #else
          cptr->key = 0;
        #endif /* BLOCK_ALLOCATION */
        }

      #if defined(NICKSERVICES) && defined(CHANNELSERVICES)
        cs_CheckModes(lptr,
          FindChan(cptr->name),
          !add,
          MODE_K,
          0);
      #endif

        break;
      } /* case 'k' */

      /*
       * Channel forwarding target
       */
      case 'f':
      {
        ++argidx;
        if (argidx >= argcnt)
          break;

      #ifndef BLOCK_ALLOCATION
        if (cptr->forward)
          MyFree(cptr->forward);
      #endif

        if (add)
        {
        #ifdef BLOCK_ALLOCATION
          strncpy(cptr->forward, modeargs[argidx], CHANNELLEN);
          cptr->forward[CHANNELLEN] = '\0';
        #else
          cptr->forward = MyStrdup(modeargs[argidx]);
        #endif /* BLOCK_ALLOCATION */
        }
        else
        {
        #ifdef BLOCK_ALLOCATION
          cptr->forward[0] = '\0';
        #else
          cptr->forward = 0;
        #endif /* BLOCK_ALLOCATION */
        }

      #if defined(NICKSERVICES) && defined(CHANNELSERVICES)
        cs_CheckModes(lptr,
          FindChan(cptr->name),
          !add,
          MODE_F,
          0);
      #endif

        break;
      } /* case 'f' */

      /*
       * Channel ban
       */
      case 'b':
      {
        ++argidx;
        if (argidx >= argcnt)
          break;

	/* if it's a forwarding ban like nick!ident@host!#channel
	 * just drop the forward channel
	 * found by CheeToS  -- jilles */
	p = strchr(modeargs[argidx], '!');
	if (p != NULL)
	{
	  p = strchr(p + 1, '!');
	  if (p != NULL)
	    *p = '\0';
	}

        if (add)
          AddBan(who, cptr, modeargs[argidx]);
        else
          DeleteBan(cptr, modeargs[argidx]);

	if (p != NULL)
	  *p = '!';

        break;
      } /* case 'b' */

#ifdef GECOSBANS
      /*
       * Channel deny
       */
      case 'd':
      {
        ++argidx;
        if (argidx >= argcnt)
          break;

        if (add)
          AddGecosBan(who, cptr, modeargs[argidx]);
        else
          DeleteGecosBan(cptr, modeargs[argidx]);

        break;
      } /* case 'd' */
#endif /* GECOSBANS */

      /*
       * Channel exception
       */
      case 'e':
      {
        ++argidx;
        if (argidx >= argcnt)
          break;

        if (add)
          AddException(who, cptr, modeargs[argidx]);
        else
          DeleteException(cptr, modeargs[argidx]);

        break;
      } /* case 'e' */

#ifdef HYBRID7
    /* Channel invite exception -Janos */
     case 'I':
     {
       ++argidx;
       if (argidx >= argcnt)
         break;

       if (add)
         AddInviteException(who, cptr, modeargs[argidx]);
       else
         DeleteInviteException(cptr, modeargs[argidx]);
       break;
     } /* case 'I' */
#endif /* HYBRID7 */

      default:
      {
        int modeflag = 0;

        if (ch == 's')
          modeflag = MODE_S;
        else if (ch == 'p')
          modeflag = MODE_P;
        else if (ch == 'n')
          modeflag = MODE_N;
        else if (ch == 't')
          modeflag = MODE_T;
        else if (ch == 'm')
          modeflag = MODE_M;
        else if (ch == 'i')
          modeflag = MODE_I;
        else if (ch == 'r')
          modeflag = MODE_R;
        else if (ch == 'z')
          modeflag = MODE_Z;
        else if (ch == 'P')
          modeflag = MODE_CAPP;
#if 0
        /* doesn't exist in 1.0.34 */
        else if (ch == 'F')
          modeflag = MODE_CAPF;
#endif
        else if (ch == 'Q')
          modeflag = MODE_CAPQ;
#ifdef HYBRID7
        else if (ch == 'a')
          modeflag = MODE_A;
#endif 
        else if (ch == 'c')
          modeflag = MODE_C;
        else if (ch == 'g')
          modeflag = MODE_G;
        else if (ch == 'L')
          modeflag = MODE_CAPL;
        else if (ch == 'R')
          modeflag = MODE_CAPR;

        if (modeflag)
        {
          if (add)
            cptr->modes |= modeflag;
          else
            cptr->modes &= ~modeflag;
        }

      #if defined(NICKSERVICES) && defined(CHANNELSERVICES)
        if (modeflag)
          cs_CheckModes(lptr,
            FindChan(cptr->name),
            !add,
            modeflag,
            0);
      #endif

        break;
      } /* default: */
    } /* switch (*tmp) */
  } /* for (tmp = modes; *tmp; ++tmp) */

  MyFree(modeargs);

#if defined(NICKSERVICES) && defined(CHANNELSERVICES)
  if ((cs_deoped) && (!FloodCheck(cptr, lptr, Me.csptr, 0)))
  {
    /* reop ChanServ */
    #ifdef SAVE_TS
      cs_part(cptr);
      cs_join(FindChan(cptr->name));
    #else
      toserv(":%s MODE %s +o %s\n",
        n_ChanServ,
        cptr->name,
        n_ChanServ);
    #endif

    if (!lptr)
      putlog(LOG1, "%s: %s attempted to deop %s",
        cptr->name,
        who,
        n_ChanServ);
    else
      putlog(LOG1, "%s: %s!%s@%s attempted to deop %s",
        cptr->name,
        lptr->nick,
        lptr->username,
        lptr->hostname,
        n_ChanServ);
  }
#endif /* defined(NICKSERVICES) && defined(CHANNELSERVICES) */

} /* UpdateChanModes() */
Ejemplo n.º 12
0
void
RemoveFromChannel(struct Channel *cptr, struct Luser *lptr)

{
  struct UserChannel *tempchan,
                     *prev = NULL;
  struct ChannelUser *tempuser,
                     *prev2 = NULL;

  if (!cptr || !lptr)
    return;

  SendUmode(OPERUMODE_P,
    "*** Channel part: %s (%s)",
    lptr->nick,
    cptr->name);

  /* Is this the contact? */
#ifdef CHANNELSERVICES
  {
    struct NickInfo *nptr;
    struct ChanInfo *ciptr;
    if ((nptr = FindNick(lptr->nick)) && (ciptr = FindChan(cptr->name)))
      {
	if (nptr->flags & NS_IDENTIFIED)
	  {
	    if (ciptr->contact && irccmp(lptr->nick, ciptr->contact) == 0)
	      /* That's the contact joining. Update activity timer */
	      ciptr->last_contact_active = current_ts;
	    if (ciptr->alternate && irccmp(lptr->nick, ciptr->alternate) == 0)
	      ciptr->last_alternate_active = current_ts;
	  }
      }
  }
#endif

  /* remove cptr from lptr's chan list */
  for (tempchan = lptr->firstchan; tempchan; tempchan = tempchan->next)
  {
    if (cptr == tempchan->chptr)
    {
      if (prev)
        prev->next = tempchan->next;
      else
        lptr->firstchan = tempchan->next;
      MyFree(tempchan);
      tempchan = NULL;
      break;
    }
    prev = tempchan;
  }

  /* remove lptr from cptr's nick list */
  for (tempuser = cptr->firstuser; tempuser; tempuser = tempuser->next)
  {
    if (lptr == tempuser->lptr)
    {
      if (prev2)
        prev2->next = tempuser->next;
      else
        cptr->firstuser = tempuser->next;
      MyFree(tempuser);
      tempuser = NULL;
      --cptr->numusers;
      break;
    }
    prev2 = tempuser;
  }

  if (cptr->numusers == 0)
    DeleteChannel(cptr); /* the last nick left the chan, erase it */
} /* RemoveFromChannel() */