+void
+chm_halfop(struct Client *source_p, struct Channel *chptr,
+ int alevel, int parc, int *parn,
+ const char **parv, int *errors, int dir, char c, long mode_type)
+{
+ struct membership *mstptr;
+ const char *halfopnick;
+ struct Client *targ_p;
+ int override = 0;
+
+ if(!ConfigChannel.use_halfop)
+ {
+ if(*errors & SM_ERR_UNKNOWN)
+ return;
+ *errors |= SM_ERR_UNKNOWN;
+ sendto_one(source_p, form_str(ERR_UNKNOWNMODE), me.name, source_p->name, c);
+ return;
+ }
+
+ if(alevel != CHFL_CHANOP && alevel != CHFL_OWNER)
+ {
+ if(IsOverride(source_p))
+ override = 1;
+ else
+ {
+
+ if(!(*errors & SM_ERR_NOOPS))
+ sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
+ me.name, source_p->name, chptr->chname);
+ *errors |= SM_ERR_NOOPS;
+ return;
+ }
+ }
+
+ if((dir == MODE_QUERY) || (parc <= *parn))
+ return;
+
+ halfopnick = parv[(*parn)];
+ (*parn)++;
+
+ /* empty nick */
+ if(EmptyString(halfopnick))
+ {
+ sendto_one_numeric(source_p, ERR_NOSUCHNICK, form_str(ERR_NOSUCHNICK), "*");
+ return;
+ }
+
+ if((targ_p = find_chasing(source_p, halfopnick, NULL)) == NULL)
+ {
+ return;
+ }
+
+ mstptr = find_channel_membership(chptr, targ_p);
+
+ if(mstptr == NULL)
+ {
+ if(!(*errors & SM_ERR_NOTONCHANNEL) && MyClient(source_p))
+ sendto_one_numeric(source_p, ERR_USERNOTINCHANNEL,
+ form_str(ERR_USERNOTINCHANNEL), halfopnick, chptr->chname);
+ *errors |= SM_ERR_NOTONCHANNEL;
+ return;
+ }
+
+ if(MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
+ return;
+
+ if(dir == MODE_ADD)
+ {
+ if(targ_p == source_p)
+ {
+ no_override_deop = 1;
+ /* Don't reject modes from remote. It desyncs, and this is perfectly
+ * legitimate from a remote override oper.
+ if(!override)
+ return;
+ */
+ }
+
+ mode_changes[mode_count].letter = c;
+ mode_changes[mode_count].dir = MODE_ADD;
+ mode_changes[mode_count].caps = 0;
+ mode_changes[mode_count].nocaps = 0;
+ mode_changes[mode_count].mems = ALL_MEMBERS;
+ mode_changes[mode_count].id = targ_p->id;
+ mode_changes[mode_count].arg = targ_p->name;
+ mode_changes[mode_count].override = override;
+ mode_changes[mode_count++].client = targ_p;
+
+ mstptr->flags |= CHFL_HALFOP;
+ }
+ else
+ {
+ if(MyClient(source_p) && IsService(targ_p))
+ {
+ sendto_one(source_p, form_str(ERR_ISCHANSERVICE),
+ me.name, source_p->name, targ_p->name, chptr->chname);
+ return;
+ }
+
+ mode_changes[mode_count].letter = c;
+ mode_changes[mode_count].dir = MODE_DEL;
+ mode_changes[mode_count].caps = 0;
+ mode_changes[mode_count].nocaps = 0;
+ mode_changes[mode_count].mems = ALL_MEMBERS;
+ mode_changes[mode_count].id = targ_p->id;
+ mode_changes[mode_count].arg = targ_p->name;
+ mode_changes[mode_count].override = override;
+ mode_changes[mode_count++].client = targ_p;
+
+ mstptr->flags &= ~CHFL_HALFOP;
+ }
+}
+