// --------------------------------------------------------------------------
// Citadel: GrpMembr.CPP
//
// Code edit group membership.

#include "ctdl.h"
#pragma hdrstop

#include "log.h"
#include "msg.h"
#include "group.h"
#include "boolexpr.h"
#include "menus.h"
#include "miscovl.h"

// --------------------------------------------------------------------------
// Contents
//
// groupfunc()		aide fn to add/remove group members
// globalgroup()	sysop fn to add/remove group members (global)
// globaluser() 	sysop fn to add/remove user from groups (global)

void OperatorSpecificMembership(void)
	{
	char String[256], Prompt[128];

	doCR();
	sprintf(Prompt, getsysmsg(90), cfg.Lgroup_nym);

	do
		{
		getString(Prompt, String, 255, TRUE, ECHO, ns);

		if (*String == '?')
			{
			ListGroups(FALSE);
			}
		} while (*String == '?');

	if (*String)
		{
		BoolExpr Expression;

		if (!CreateBooleanExpression(String, TestGroupOrMetaExists,
				Expression))
			{
			CRmPrintfCR(getmsg(947), cfg.Lgroup_nym);
			}
		else
			{
			label groupname;
			g_slot groupslot;
			int add;

			switch (toupper(DoMenuPrompt(pctss, getmsg(952))))
				{
				case 'A':
					{
					mPrintfCR(getmsg(358));
					add = 1;
					break;
					}

//				case 'B':
//				case 10:
//				case 13:
				default:
					{
					mPrintfCR(getmsg(953));
					add = 0;
					break;
					}

				case 'R':
					{
					mPrintfCR(getmsg(359));
					add = 2;
					break;
					}

				case '?':
					{
					showMenu(M_GRPGLOB);
					return;
					}
				}

			do
				{
				getString(cfg.Lgroup_nym, groupname, LABELSIZE, TRUE, ECHO,
						ns);

				if (*groupname == '?')
					{
					ListGroups(FALSE);
					}
				} while (*groupname == '?');

			groupslot = FindGroupByPartialName(groupname, FALSE);

			if (groupslot != CERROR &&
					GroupData->GetEntry(groupslot)->IsHidden() &&
					!TI()CurrentUser->IsInGroup(groupslot))
				{
				groupslot = CERROR;
				}

			if (groupslot == CERROR || !(*groupname))
				{
				if (*groupname)
					{
					CRmPrintfCR(getmsg(946), cfg.Lgroup_nym, groupname);
					}

				return;
				}

			const GroupEntry * const GE = GroupData->GetEntry(groupslot);

			if (GE->IsLocked() && !TI()CurrentUser->IsSysop())
				{
				CRmPrintf(getmsg(954), cfg.Ugroup_nym);
				return;
				}

			for (l_slot i = 0; i < cfg.MAXLOGTAB; i++)
				{
				TI()UserControl.SetOutFlag(OUTOK);

				if (TI()UserControl.CheckInput(FALSE))
					{
					break;
					}

				TI()UserControl.SetOutFlag(IMPERVIOUS);

				if (LogTab->GetEntry(i)->IsInuse())
					{
					LogEntry2 Log2(cfg.maxgroups);

					const l_index logNo = LogTab->GetEntry(i)->GetLogIndex();

					if (Log2.Load(logNo))
						{
						TI()Log2ForGroupTester = &Log2;
						TI()SlotForGroupTester = i;

						if (EvaluateBooleanExpression(Expression,
								GroupWithMetaTester))
							{
							const Bool StartedInGroup =
									Log2.IsInGroup(groupslot);

							if (add == 0 ||
									(StartedInGroup && add == 2) ||
									(!StartedInGroup && add == 1))
								{
								const char * const UN =
										LogTab->GetEntry(i)->GetName();

								char query[128];
								int yn;

								sprintf(query, StartedInGroup ? getmsg(955) :
										getmsg(956), UN, cfg.Lgroup_nym,
										GE->GetName());

								yn = getYesNo(query, 3);
								if (yn == 2)
									{
									SaveAideMess(GE->GetName());
									return;
									}

								if (yn)
									{
									char trapstr[256];

									Log2.SetInGroup(groupslot, !StartedInGroup);

									sprintf(trapstr, StartedInGroup ?
											getmsg(949) : getmsg(951), UN,
											GE->GetName(),
											TI()CurrentUser->GetName());

									trap(trapstr, T_SYSOP);

									sprintf(trapstr, StartedInGroup ?
											getmsg(1370) : getmsg(1371),
											UN, cfg.Lgroup_nym,
											GE->GetName(),
											TI()CurrentUser->GetName());

									amPrintf(getmsg(1434), trapstr, bn);

									Log2.Save(logNo);

									// see if it is us
									if (TI()loggedIn && SameString(UN,
											TI()CurrentUser->GetName()))
										{
										TI()CurrentUser->SetInGroup(groupslot,
												!StartedInGroup);
										}
									}
								}
							}
						}
					}
				}

			SaveAideMess(GE->GetName());
			}
		}
	}


// --------------------------------------------------------------------------
// groupfunc(): Aide fn to add/remove group members.

void groupfunc(const char *grpName, const char *userName, Bool addToGroup)
	{
	label who;
	label groupname;
	g_slot groupslot;
	char line[128];

	if (!grpName)
		{
		do
			{
			getString(cfg.Lgroup_nym, groupname, LABELSIZE, TRUE, ECHO, ns);

			if (*groupname == '?')
				{
				ListGroups(FALSE);
				}
			} while (*groupname == '?');
		}
	else
		{
		CopyStringToBuffer(groupname, grpName, LABELSIZE);
		}

	if (!*groupname)
		{
		return;
		}

	// If grpName specified, ignore user being in the group
	groupslot = FindGroupByPartialName(groupname, !!grpName);

	if (groupslot != CERROR && !grpName)
		{
		if ((GroupData->GetEntry(groupslot)->IsLocked() &&
				!TI()CurrentUser->IsSysop())
			||
			(GroupData->GetEntry(groupslot)->IsHidden() &&
				!TI()CurrentUser->IsInGroup(groupslot) &&
				!onConsole))
			{
			groupslot = CERROR;
			}
		}

	if (groupslot == CERROR)
		{
		if (grpName)
			{
			CRmPrintf(getmsg(946), cfg.Lgroup_nym, grpName);
			}
		else
			{
			CRmPrintfCR(getmsg(947), cfg.Lgroup_nym);
			}
		}
	else
		{
		l_slot logNo;

		if (!userName)
			{
			do
				{
				getString(getmsg(599), who, LABELSIZE, TRUE, ECHO,
						TI()loggedIn ? TI()CurrentUser->GetName() : ns);

				if (*who == '?')
					{
					ListUsers(TI()CurrentUser->IsAide());
					}
				} while (*who == '?');

			normalizeString(who);
			logNo = FindPersonByPartialName(who);
			}
		else
			{
			CopyStringToBuffer(who, userName, LABELSIZE);
			logNo = FindPersonByName(who);
			}

		if (logNo == CERROR || !*who)
			{
			if (*who)
				{
				CRmPrintfCR(getmsg(595), who);
				}
			}
		else
			{
			LogEntry2 Log2(cfg.maxgroups);

			if (Log2.Load(LogTab->GetEntry(logNo)->GetLogIndex()))
				{
				CopyStringToBuffer(who, LogTab->GetEntry(logNo)->GetName(),
						sizeof(who) - 1);
				CopyStringToBuffer(groupname, GroupData->GetEntry(groupslot)->GetName(),
						sizeof(groupname) - 1);

				const Bool StartedInGroup = Log2.IsInGroup(groupslot);

				sprintf(line, StartedInGroup ? getmsg(955) : getmsg(956),
						who, cfg.Lgroup_nym, groupname);

				if ((userName && (addToGroup != StartedInGroup)) ||
						(!userName && getYesNo(line, 0)))
					{
					Log2.SetInGroup(groupslot, !StartedInGroup);

					if (!userName)
						{
						char TrapString[256];

						sprintf(TrapString, StartedInGroup ? getmsg(949) :
								getmsg(951), who, groupname,
								TI()CurrentUser->GetName());

						trap(TrapString, T_AIDE);

						Message *Msg = new Message;

						if (Msg)
							{
							Msg->SetGroup(groupname);
							Msg->SetRoomNumber(AIDEROOM);

							sprintf(TrapString, StartedInGroup ? getmsg(1370) :
									getmsg(1371), who, cfg.Lgroup_nym,
									groupname, TI()CurrentUser->GetName());

							Msg->SetText(TrapString);
							systemMessage(Msg);

							delete Msg;
							}
						else
							{
							mPrintf(getmsg(188), getmsg(657));
							}
						}

					Log2.Save(LogTab->GetEntry(logNo)->GetLogIndex());

					// see if it is us
					if (TI()loggedIn &&
							SameString(TI()CurrentUser->GetName(), who))
						{
						TI()CurrentUser->SetInGroup(groupslot, !StartedInGroup);
						}
					}
				}
			}
		}
	}


// --------------------------------------------------------------------------
// globalgroup(): Sysop fn to add/remove group members (global).

void globalgroup(const char *theGroup, Bool addAll)
	{
	label groupname;
	g_slot groupslot;
	int add;

	if (theGroup && *theGroup)
		{
		if (addAll)
			{
			add = 1;
			}
		else
			{
			add = 0;	// both
			}

		CopyStringToBuffer(groupname, theGroup, LABELSIZE);
		}
	else
		{
		mPrintf(pctss, getmsg(952));

		switch (toupper(iCharNE()))
			{
			case 'A':
				{
				mPrintfCR(getmsg(358));
				add = 1;
				break;
				}

			case 'B':
			case 10:
			case 13:
			default:
				{
				mPrintfCR(getmsg(953));
				add = 0;
				break;
				}

			case 'R':
				{
				mPrintfCR(getmsg(359));
				add = 2;
				break;
				}

			case '?':
				{
				showMenu(M_GRPGLOB);
				return;
				}
			}

		do
			{
			getString(cfg.Lgroup_nym, groupname, LABELSIZE, TRUE, ECHO, ns);

			if (*groupname == '?')
				{
				ListGroups(FALSE);
				}
			} while (*groupname == '?');
		}

	groupslot = FindGroupByPartialName(groupname, FALSE);

	if (groupslot != CERROR && GroupData->GetEntry(groupslot)->IsHidden() &&
			!TI()CurrentUser->IsInGroup(groupslot))
		{
		groupslot = CERROR;
		}

	if (groupslot == CERROR || !(*groupname))
		{
		if (*groupname)
			{
			CRmPrintfCR(getmsg(946), cfg.Lgroup_nym, groupname);
			}

		return;
		}

	const GroupEntry * const GE = GroupData->GetEntry(groupslot);

	if (GE->IsLocked() && !TI()CurrentUser->IsSysop())
		{
		CRmPrintf(getmsg(954), cfg.Ugroup_nym);
		return;
		}

	for (l_slot i = 0; i < cfg.MAXLOGTAB; i++)
		{
		TI()UserControl.SetOutFlag(OUTOK);

		if (TI()UserControl.CheckInput(FALSE))
			{
			break;
			}

		TI()UserControl.SetOutFlag(IMPERVIOUS);

		if (LogTab->GetEntry(i)->IsInuse())
			{
			LogEntry2 Log2(cfg.maxgroups);

			const l_index logNo = LogTab->GetEntry(i)->GetLogIndex();

			if (Log2.Load(logNo))
				{
				const StartedInGroup = Log2.IsInGroup(groupslot);

				if (add == 0 ||
						(StartedInGroup && add == 2) ||
						(!StartedInGroup && add == 1))
					{
					const char * const UN = LogTab->GetEntry(i)->GetName();

					int yn;

					if (!addAll)
						{
						char query[128];

						sprintf(query, StartedInGroup ? getmsg(955) :
								getmsg(956), UN, cfg.Lgroup_nym,
								GE->GetName());

						yn = getYesNo(query, 3);
						if (yn == 2)
							{
							SaveAideMess(GE->GetName());
							return;
							}
						}

					if (addAll || yn)
						{
						char trapstr[256];

						Log2.SetInGroup(groupslot, !StartedInGroup);

						sprintf(trapstr, StartedInGroup ? getmsg(949) :
								getmsg(951), UN, GE->GetName(),
								TI()CurrentUser->GetName());

						trap(trapstr, T_SYSOP);

						sprintf(trapstr, StartedInGroup ? getmsg(1370) :
								getmsg(1371), UN, cfg.Lgroup_nym,
								GE->GetName(), TI()CurrentUser->GetName());

						amPrintf(getmsg(1434), trapstr, bn);

						Log2.Save(logNo);

						// see if it is us
						if (TI()loggedIn && SameString(UN,
								TI()CurrentUser->GetName()))
							{
							TI()CurrentUser->SetInGroup(groupslot,
									!StartedInGroup);
							}
						}
					}
				}
			}
		}

	SaveAideMess(GE->GetName());
	}


// --------------------------------------------------------------------------
// globaluser(): Sysop function to add/remove user from groups (global).

void globaluser(void)
	{
	label who;
	l_slot logNo;

	do
		{
		getString(getmsg(599), who, LABELSIZE, TRUE, ECHO,
				TI()loggedIn ? TI()CurrentUser->GetName() : ns);

		if (*who == '?')
			{
			ListUsers(TI()CurrentUser->IsAide());
			}
		} while (*who == '?');
	normalizeString(who);

	if (!*who)
		{
		return;
		}

	logNo = FindPersonByPartialName(who);

	if (logNo == CERROR)
		{
		CRmPrintfCR(getmsg(595), who);
		}
	else
		{
		Bool done;
		Bool Changed = FALSE;
		g_slot GroupSlot;
		LogEntry2 Log2(cfg.maxgroups);

		if (Log2.Load(LogTab->GetEntry(logNo)->GetLogIndex()))
			{
			CopyStringToBuffer(who, LogTab->GetEntry(logNo)->GetName(),
					sizeof(who) - 1);

			for (done = FALSE, GroupSlot = 0; !done && GroupSlot < cfg.maxgroups;
					GroupSlot++)
				{
				const GroupEntry * const GE = GroupData->GetEntry(GroupSlot);

				if (GE->IsInuse() &&
						(!GE->IsLocked() || TI()CurrentUser->IsSysop()) &&
						(!GE->IsHidden() || TI()CurrentUser->IsInGroup(GroupSlot)))
					{
					const Bool StartedInGroup = Log2.IsInGroup(GroupSlot);

					char query[128];
					int yn;

					sprintf(query, StartedInGroup ? getmsg(955) : getmsg(956),
							who, cfg.Lgroup_nym, GE->GetName());

					if ((yn = getYesNo(query, 3)) == 2)
						{
						done = TRUE;
						}
					else if (yn == 1)
						{
						Changed = TRUE;

						Log2.SetInGroup(GroupSlot, !StartedInGroup);

						char TrapString[256];

						sprintf(TrapString, StartedInGroup ? getmsg(949) :
								getmsg(951), who, GE->GetName(),
								TI()CurrentUser->GetName());

						trap(TrapString, T_SYSOP);

						sprintf(TrapString, StartedInGroup ? getmsg(1370) :
								getmsg(1371), who, cfg.Lgroup_nym,
								GE->GetName(), TI()CurrentUser->GetName());

						amPrintf(getmsg(1434), TrapString, bn);
						}
					}
				}

			if (Changed)
				{
				if (Log2.Save(LogTab->GetEntry(logNo)->GetLogIndex()))
					{
					// see if it is us
					if (TI()loggedIn && (logNo == TI()ThisSlot))
						{
						TI()CurrentUser->LogEntry2::Load(TI()ThisLog);
						}
					}
				}
			}

		SaveAideMess(GroupData->GetEntry(1)->GetName());	// Reserved_2
		}
	}

int TestGroupExists(const char *TestString)
	{
	return (FindGroupByPartialName(TestString, FALSE));
	}

// yes, this is a bit of a kludge. cope.

#define META_SYSOP		32767
#define META_AIDE		32766
#define META_NODE		32765
#define META_UNLISTED	32764
#define META_TWIT		32763
#define META_PERMANENT	32762
#define META_NETWORK	32761
#define META_NOMAIL 	32760

int TestGroupOrMetaExists(const char *TestString)
	{
	if (SameString(TestString, getmsg(658)))
		{
		return (META_SYSOP);
		}

	if (SameString(TestString, getmsg(659)))
		{
		return (META_AIDE);
		}

	if (SameString(TestString, getmsg(660)))
		{
		return (META_NODE);
		}

	if (SameString(TestString, getmsg(554)))
		{
		return (META_UNLISTED);
		}

	if (SameString(TestString, getmsg(593)))
		{
		return (META_TWIT);
		}

	if (SameString(TestString, getmsg(594)))
		{
		return (META_PERMANENT);
		}

	if (SameString(TestString, getmsg(773)))
		{
		return (META_NETWORK);
		}

	if (SameString(TestString, getmsg(775)))
		{
		return (META_NOMAIL);
		}

	return (FindGroupByPartialName(TestString, FALSE));
	}

void ShowGroup(g_slot Group)
	{
	mPrintf(getmsg(1491), GroupData->GetEntry(Group)->GetName());
	}

void ShowGroupWithMeta(g_slot Group)
	{
	switch (Group)
		{
		case META_SYSOP:
			{
			mPrintf(getmsg(1491), getmsg(658));
			break;
			}

		case META_AIDE:
			{
			mPrintf(getmsg(1491), getmsg(659));
			break;
			}

		case META_NODE:
			{
			mPrintf(getmsg(1491), getmsg(660));
			break;
			}

		case META_UNLISTED:
			{
			mPrintf(getmsg(1491), getmsg(554));
			break;
			}

		case META_TWIT:
			{
			mPrintf(getmsg(1491), getmsg(593));
			break;
			}

		case META_PERMANENT:
			{
			mPrintf(getmsg(1491), getmsg(594));
			break;
			}

		case META_NETWORK:
			{
			mPrintf(getmsg(1491), getmsg(773));
			break;
			}

		case META_NOMAIL:
			{
			mPrintf(getmsg(1491), getmsg(775));
			break;
			}

		default:
			{
			mPrintf(getmsg(1491), GroupData->GetEntry(Group)->GetName());
			break;
			}
		}
	}

Bool GroupNameTester(g_slot GroupSlot)
	{
	return (SameString(GroupData->GetEntry(GroupSlot)->GetName(),
			TI()GroupNameForNameTester));
	}

Bool GroupTester(g_slot GroupSlot)
	{
	return (TI()Log2ForGroupTester->IsInGroup(GroupSlot));
	}

Bool GroupWithMetaTester(g_slot GroupSlot)
	{
	switch (GroupSlot)
		{
		case META_SYSOP:
			{
			return (LogTab->GetEntry(TI()SlotForGroupTester)->IsSysop());
			}

		case META_AIDE:
			{
			return (LogTab->GetEntry(TI()SlotForGroupTester)->IsAide());
			}

		case META_NODE:
			{
			return (LogTab->GetEntry(TI()SlotForGroupTester)->IsNode());
			}

		case META_UNLISTED:
			{
			return (LogTab->GetEntry(TI()SlotForGroupTester)->IsUnlisted());
			}

		case META_TWIT:
			{
			return (LogTab->GetEntry(TI()SlotForGroupTester)->IsProblem());
			}

		case META_PERMANENT:
			{
			return (LogTab->GetEntry(TI()SlotForGroupTester)->IsPermanent());
			}

		case META_NETWORK:
			{
			return (LogTab->GetEntry(TI()SlotForGroupTester)->IsNetUser());
			}

		case META_NOMAIL:
			{
			return (!LogTab->GetEntry(TI()SlotForGroupTester)->IsMail());
			}

		default:
			{
			return (TI()Log2ForGroupTester->IsInGroup(GroupSlot));
			}
		}
	}
