Example #1
0
void ChannelAgent::MessageReceived(BMessage* msg)
{
	int32 i(0);

	switch (msg->what) {
	case M_USER_QUIT: {
		const char* nick(NULL);

		msg->FindString("nick", &nick);

		if (RemoveUser(nick)) {
			BMessage display;

			if (msg->FindMessage("display", &display) == B_NO_ERROR)
				ClientAgent::MessageReceived(&display);
		}
	} break;

	case M_USER_ADD: {
		const char* nick(NULL);
		bool ignore(false);

		int32 iStatus(STATUS_NORMAL_BIT);

		msg->FindString("nick", &nick);
		msg->FindBool("ignore", &ignore);
		if (nick == NULL) {
			printf("ERROR: attempted to AddUser an empty nick in ChannelAgent, channel: %s\n",
				   fId.String());
			break;
		}

		if (ignore) iStatus |= STATUS_IGNORE_BIT;

		AddUser(nick, iStatus);

		BMessage display;
		if (msg->FindMessage("display", &display) == B_NO_ERROR)
			ClientAgent::MessageReceived(&display);
	} break;

	case M_CHANGE_NICK: {
		const char* oldNick(NULL), *newNick(NULL);
		NameItem* item(NULL);
		int32 thePos(-1);

		if ((msg->FindString("oldnick", &oldNick) != B_OK) ||
			(msg->FindString("newnick", &newNick) != B_OK)) {
			printf("Error: invalid pointer, ChannelAgent::MessageReceived, M_CHANGE_NICK");
			break;
		}

		if (fMyNick.ICompare(oldNick) == 0 && !IsHidden())
			vision_app->pClientWin()->pStatusView()->SetItemValue(STATUS_NICK, newNick);

		if (((thePos = FindPosition(oldNick)) >= 0) &&
			((item = (static_cast<NameItem*>(fNamesList->ItemAt(thePos)))) != 0)) {
			item->SetName(newNick);
			fNamesList->SortItems(SortNames);
			if (fLastExpansion.ICompare(oldNick, fLastExpansion.Length()) == 0) {
				int32 count(fRecentNicks.CountItems());
				BString* name(NULL);

				for (i = 0; i < count; i++)
					if ((name = fRecentNicks.ItemAt(i))->ICompare(oldNick) == 0) {
						if (fLastExpansion.ICompare(newNick, fLastExpansion.Length()) == 0)
							name->SetTo(newNick);
						else
							delete fRecentNicks.RemoveItemAt(i);
						break;
					}
				count = fCompletionNicks.CountItems();
				for (i = 0; i < count; i++)
					if ((name = fCompletionNicks.ItemAt(i))->ICompare(oldNick) == 0) {
						if (fLastExpansion.ICompare(newNick, fLastExpansion.Length()) == 0)
							name->SetTo(newNick);
						else
							delete fCompletionNicks.RemoveItemAt(i);
						break;
					}
			}
		} else
			break;

		ClientAgent::MessageReceived(msg);
	} break;

	case M_CHANNEL_NAMES: {
		for (i = 0; msg->HasString("nick", i); ++i) {
			const char* nick(NULL);
			bool founder(false), protect(false), op(false), voice(false), helper(false),
				ignored(false);

			msg->FindString("nick", i, &nick);
			msg->FindBool("founder", i, &founder);
			msg->FindBool("protect", i, &protect);
			msg->FindBool("op", i, &op);
			msg->FindBool("voice", i, &voice);
			msg->FindBool("helper", i, &helper);
			msg->FindBool("ignored", i, &ignored);

			if (FindPosition(nick) < 0) {
				int32 iStatus(ignored ? STATUS_IGNORE_BIT : 0);

				if (founder) {
					++nick;
					++fOpsCount;
					iStatus |= STATUS_FOUNDER_BIT;
				} else if (protect) {
					++nick;
					++fOpsCount;
					iStatus |= STATUS_PROTECTED_BIT;
				} else if (op) {
					++nick;
					++fOpsCount;
					iStatus |= STATUS_OP_BIT;
				} else if (voice) {
					++nick;
					iStatus |= STATUS_VOICE_BIT;
				} else if (helper) {
					++nick;
					iStatus |= STATUS_HELPER_BIT;
				} else
					iStatus |= STATUS_NORMAL_BIT;

				fUserCount++;

				fNamesList->AddItem(new NameItem(nick, iStatus));
			}
		}

		fNamesList->SortItems(SortNames);

		if (!IsHidden()) {
			BString buffer;
			buffer << fOpsCount;
			vision_app->pClientWin()->pStatusView()->SetItemValue(STATUS_OPS, buffer.String());

			buffer = "";
			buffer << fUserCount;
			vision_app->pClientWin()->pStatusView()->SetItemValue(STATUS_USERS, buffer.String());
		}
	} break;

	case M_RESIZE_VIEW: {
		BPoint point;
		msg->FindPoint("loc", &point);
		point.x -= Frame().left;
		float offset((int32)(point.x - (fNamesScroll->Frame().left)));
		fResize->MoveBy(offset, 0.0);
		fTextScroll->ResizeBy(offset, 0.0);
		fNamesScroll->ResizeBy(-offset, 0.0);
		fNamesScroll->MoveBy(offset, 0.0);
		BRect namesRect(0, 0, fNamesScroll->Bounds().Width(), 0);
		vision_app->SetRect("namesListRect", namesRect);
	} break;

	case M_SERVER_DISCONNECT: {
		// clear names list on disconnect
		fNamesList->ClearList();
		fOpsCount = 0;
		fUserCount = 0;

		// clear heuristics completion list - this ensures that no stale nicks are left
		// over in it after reconnect -- list will quickly be rebuilt anyhow if there
		// is any conversation whatsoever going on
		while (fRecentNicks.CountItems() > 0) delete fRecentNicks.RemoveItemAt(0L);

	} break;

	case M_REJOIN: {
		const char* newNick(NULL);

		if (msg->FindString("nickname", &newNick) != B_OK) {
			printf("Error: ChannelAgent::MessageReceived, M_REJOIN: invalid pointer\n");
			break;
		}

		fMyNick = newNick; // update nickname (might have changed on reconnect)

		if (!IsHidden())
			vision_app->pClientWin()->pStatusView()->SetItemValue(STATUS_NICK, fMyNick.String());

		Display(S_CHANNEL_RECON_REJOIN B_UTF8_ELLIPSIS "\n", C_ERROR, C_BACKGROUND, F_SERVER);

		// send join cmd
		BMessage send(M_SERVER_SEND);
		AddSend(&send, "JOIN ");
		AddSend(&send, fId);
		if (fChanKey != "") {
			AddSend(&send, " ");
			AddSend(&send, fChanKey);
		}
		AddSend(&send, endl);
	} break;

	case M_CHANNEL_TOPIC: {
		const char* theTopic(NULL);
		BString buffer;

		if (msg->FindString("topic", &theTopic) != B_OK) {
			printf("ChannelAgent::MessageReceived, M_CHANNEL_TOPIC: invalid pointer\n");
			break;
		}
		fTopic = theTopic;

		if (!IsHidden())
			vision_app->pClientWin()->pStatusView()->SetItemValue(
				STATUS_META, FilterCrap(theTopic, true).String());

		BMessage display;

		if (msg->FindMessage("display", &display) == B_NO_ERROR)
			ClientAgent::MessageReceived(&display);
	} break;

	case M_OPEN_MSGAGENT: {
		const char* theNick(NULL);
		msg->FindString("nick", &theNick);

		if (theNick == NULL) {
			NameItem* myUser;
			int32 pos = fNamesList->CurrentSelection();
			if (pos >= 0) {
				myUser = static_cast<NameItem*>(fNamesList->ItemAt(pos));
				BString targetNick = myUser->Name();
				msg->AddString("nick", targetNick.String());
			}
		}

		fSMsgr.SendMessage(msg);
	} break;

	case M_CHANNEL_GOT_KICKED: {
		const char* theChannel(NULL), *kicker(NULL), *rest(NULL);

		if ((msg->FindString("channel", &theChannel) != B_OK) ||
			(msg->FindString("kicker", &kicker) != B_OK) ||
			(msg->FindString("rest", &rest) != B_OK)) {
			printf("Error: ClientAgent::MessageReceived, M_CHANNEL_GOT_KICKED, invalid pointer\n");
			break;
		}

		BMessage wegotkicked(M_DISPLAY); // "you were kicked"
		BString buffer;
		buffer += S_CHANNEL_GOT_KICKED;
		buffer += theChannel;
		buffer += " " S_CHANNEL_GOT_KICKED2 " ";
		buffer += kicker;
		buffer += " (";
		buffer += rest;
		buffer += ")\n";
		PackDisplay(&wegotkicked, buffer.String(), C_QUIT, C_BACKGROUND, F_TEXT);

		// clean up
		fNamesList->ClearList();
		fOpsCount = 0;
		fUserCount = 0;

		fMsgr.SendMessage(&wegotkicked);

		BMessage attemptrejoin(M_DISPLAY); // "you were kicked"
		buffer = S_CHANNEL_REJOIN;
		buffer += theChannel;
		buffer += B_UTF8_ELLIPSIS "\n";
		PackDisplay(&attemptrejoin, buffer.String(), C_QUIT, C_BACKGROUND, F_TEXT);
		fMsgr.SendMessage(&attemptrejoin);

		BMessage send(M_SERVER_SEND);
		AddSend(&send, "JOIN ");
		AddSend(&send, theChannel);
		if (fChanKey != "") {
			AddSend(&send, " ");
			AddSend(&send, fChanKey);
		}
		AddSend(&send, endl);
	} break;

	case M_CHANNEL_MODE: {
		ModeEvent(msg);
	} break;

	case M_CHANNEL_MSG: {
		bool hasNick(false);
		BString tempString, theNick, knownAs;
		msg->FindString("msgz", &tempString);
		msg->FindString("nick", &theNick);
		if (theNick != fMyNick) FirstKnownAs(tempString, knownAs, &hasNick);

		if (IsHidden()) {
			UpdateStatus((hasNick) ? WIN_NICK_BIT : WIN_NEWS_BIT);

			if (hasNick) {
				if (tempString[0] == '\1') {
					tempString.RemoveFirst("\1ACTION ");
					tempString.RemoveLast("\1");
				}

				BNotification notification(B_INFORMATION_NOTIFICATION);
				notification.SetGroup(BString("Vision"));
				entry_ref ref = vision_app->AppRef();
				notification.SetOnClickFile(&ref);
				notification.SetTitle(fServerName.String());
				BString content;
				content.SetToFormat("%s - %s said: %s", fId.String(), theNick.String(),
									tempString.String());
				notification.SetContent(content);
				notification.Send();
			}
		} else if (hasNick)
			system_beep(kSoundEventNames[(uint32)seNickMentioned]);

		ClientAgent::MessageReceived(msg);
	} break;

	case M_CHANNEL_MODES: {
		const char* mode(NULL), *chan(NULL), *msgz(NULL);

		if ((msg->FindString("mode", &mode) != B_OK) || (msg->FindString("chan", &chan) != B_OK) ||
			(msg->FindString("msgz", &msgz) != B_OK)) {
			printf("Error: ChannelAgent::MessageReceived, M_CHANNEL_MODES: invalid pointer\n");
			break;
		}

		if (fId.ICompare(chan) == 0) {
			BString realMode(GetWord(mode, 1));
			int32 place(2);

			if (realMode.FindFirst("l") >= 0) fChanLimit = GetWord(mode, place++);

			if (realMode.FindFirst("k") >= 0) {
				fChanKey = GetWord(mode, place++);

				// u2 may not send the channel key, thats why we stored the /join cmd
				// in a string in ParseCmd
				if (fChanKey == "*" && fIrcdtype == IRCD_UNDERNET) {
					BString tempId(fId);
					tempId.Remove(0, 1); // remove any #, &, !, blah.

					if (vision_app->pClientWin()->joinStrings.FindFirst(tempId) < 1) {
						// can't find the join cmd for this channel in joinStrings!
					} else {
						BString joinStringsL(vision_app->pClientWin()->joinStrings);

						// FindLast to make sure we get the last attempt (user might have
						// tried several keys)
						int32 idPos(joinStringsL.FindLast(tempId));
						BString tempKeyString;
						joinStringsL.MoveInto(tempKeyString, idPos, joinStringsL.Length());

						fChanKey = GetWord(tempKeyString.String(), 2);
					}
				} // end u2-kludge stuff
			}
			fChanMode = mode;
			if (!IsHidden())
				vision_app->pClientWin()->pStatusView()->SetItemValue(STATUS_MODES,
																	  fChanMode.String());
		}

		BMessage dispMsg(M_DISPLAY);
		PackDisplay(&dispMsg, msgz, C_OP, C_BACKGROUND, F_TEXT);
		BMessenger display(this);
		display.SendMessage(&dispMsg);
	} break;

	case M_NAMES_POPUP_MODE: {
		const char* inaction(NULL);

		msg->FindString("action", &inaction);

		int32 count(0), index(0);

		BString victims, targetNick, action(inaction), modechar, polarity;

		NameItem* myUser(NULL);

		/// action ///
		if (action.FindFirst("voice") >= 0)
			modechar = "v";
		else if (action.FindFirst("op") >= 0)
			modechar = "o";
		else
			break;

		/// polarity ///
		if (action.FindFirst("de") >= 0)
			polarity += " -";
		else
			polarity += " +";

		/// iterate ///
		while ((i = fNamesList->CurrentSelection(index++)) >= 0) {
			myUser = static_cast<NameItem*>(fNamesList->ItemAt(i));
			targetNick = myUser->Name();

			victims += " ";
			victims += targetNick;
			count++;
		}

		BString command("/mode ");
		command += fId;
		command += polarity;

		for (i = 0; i < count; i++) command += modechar;

		command += victims;

		ParseCmd(command.String());
	} break;

	case M_NAMES_POPUP_CTCP: {
		const char* inaction(NULL);

		msg->FindString("action", &inaction);

		int32 index(0);
		BString victims, targetNick, action(inaction);
		NameItem* myUser(NULL);
		action.ToUpper();

		/// iterate ///
		while ((i = fNamesList->CurrentSelection(index++)) >= 0) {
			myUser = static_cast<NameItem*>(fNamesList->ItemAt(i));
			targetNick = myUser->Name();

			victims += targetNick;
			victims += ",";
		}

		victims.RemoveLast(",");

		BString command("/ctcp ");
		command += victims;
		command += " ";
		command += action;

		ParseCmd(command.String());
	} break;

	case M_NAMES_POPUP_WHOIS: {
		int32 index(0);
		BString victims, targetNick;
		NameItem* myUser(NULL);

		/// iterate ///
		while ((i = fNamesList->CurrentSelection(index++)) >= 0) {
			myUser = static_cast<NameItem*>(fNamesList->ItemAt(i));
			targetNick = myUser->Name();

			victims += targetNick;
			victims += ",";
		}

		victims.RemoveLast(",");

		BString command("/whois ");
		command += victims;

		ParseCmd(command.String());
	} break;

	case M_NAMES_POPUP_NOTIFY: {
		int32 index(0);
		BString victims, targetNick;
		NameItem* myUser(NULL);

		/// iterate ///
		while ((i = fNamesList->CurrentSelection(index++)) >= 0) {
			myUser = static_cast<NameItem*>(fNamesList->ItemAt(i));
			targetNick = myUser->Name();

			victims += targetNick;
			victims += " ";
		}

		victims.RemoveLast(",");

		BString command("/notify ");
		command += victims;

		ParseCmd(command.String());

	} break;

	case M_NAMES_POPUP_DCCCHAT: {
		int32 index(0);
		BString targetNick;
		NameItem* myUser(NULL);

		/// iterate ///
		while ((i = fNamesList->CurrentSelection(index++)) >= 0) {
			myUser = static_cast<NameItem*>(fNamesList->ItemAt(i));
			targetNick = myUser->Name();

			BString command("/dcc chat ");
			command += targetNick;

			ParseCmd(command.String());
		}
	} break;

	case M_NAMES_POPUP_DCCSEND: {
		int32 index(0);
		BString targetNick;
		NameItem* myUser(NULL);

		/// iterate ///
		while ((i = fNamesList->CurrentSelection(index++)) >= 0) {
			myUser = static_cast<NameItem*>(fNamesList->ItemAt(i));
			targetNick = myUser->Name();

			BString command("/dcc send ");
			command += targetNick;

			ParseCmd(command.String());
		}
	} break;

	case M_NAMES_POPUP_KICK: {
		int32 index(0);
		BString targetNick, kickMsg(vision_app->GetCommand(CMD_KICK));
		NameItem* myUser(NULL);

		/// iterate ///
		while ((i = fNamesList->CurrentSelection(index++)) >= 0) {
			myUser = static_cast<NameItem*>(fNamesList->ItemAt(i));
			targetNick = myUser->Name();

			BString command("/kick ");
			command += targetNick;
			command += " ";
			command += kickMsg;

			ParseCmd(command.String());
		}
	} break;

	case M_STATUS_ADDITEMS: {
		vision_app->pClientWin()->pStatusView()->AddItem(new StatusItem(0, ""), true);

		vision_app->pClientWin()->pStatusView()->AddItem(
			new StatusItem(S_STATUS_LAG, "", STATUS_ALIGN_LEFT), true);

		vision_app->pClientWin()->pStatusView()->AddItem(new StatusItem(0, "", STATUS_ALIGN_LEFT),
														 true);

		vision_app->pClientWin()->pStatusView()->AddItem(new StatusItem(S_STATUS_USERS, ""), true);

		vision_app->pClientWin()->pStatusView()->AddItem(new StatusItem(S_STATUS_OPS, ""), true);

		vision_app->pClientWin()->pStatusView()->AddItem(new StatusItem(S_STATUS_MODES, ""), true);

		vision_app->pClientWin()->pStatusView()->AddItem(new StatusItem("", "", STATUS_ALIGN_LEFT),
														 true);

		// The false bool for SetItemValue() tells the StatusView not to Invalidate() the view.
		// We send true on the last SetItemValue().
		vision_app->pClientWin()->pStatusView()->SetItemValue(STATUS_SERVER, fServerName.String(),
															  false);
		vision_app->pClientWin()->pStatusView()->SetItemValue(STATUS_LAG, fMyLag.String(), false);
		vision_app->pClientWin()->pStatusView()->SetItemValue(STATUS_NICK, fMyNick.String(), false);
		vision_app->pClientWin()->pStatusView()->SetItemValue(STATUS_MODES, fChanMode.String(),
															  false);
		vision_app->pClientWin()->pStatusView()->SetItemValue(
			STATUS_META, FilterCrap(fTopic.String(), true).String());

		BString buffer;
		buffer << fUserCount;
		vision_app->pClientWin()->pStatusView()->SetItemValue(STATUS_USERS, buffer.String(), false);
		buffer = "";
		buffer << fOpsCount;
		vision_app->pClientWin()->pStatusView()->SetItemValue(STATUS_OPS, buffer.String(), true);
	} break;

	case M_CHANNEL_OPTIONS_SHOW: {
		if (fChanOpt)
			fChanOpt->Activate();
		else {
			fChanOpt = new ChannelOptions(fId.String(), this);
			fChanOpt->Show();
		}
	} break;

	case M_CHANNEL_OPTIONS_CLOSE: {
		fChanOpt = NULL;
	} break;

	case M_CLIENT_QUIT: {
		if ((msg->HasBool("vision:part") && msg->FindBool("vision:part")) ||
			(msg->HasBool("vision:winlist") && msg->FindBool("vision:winlist"))) {
			BMessage send(M_SERVER_SEND);
			AddSend(&send, "PART ");
			AddSend(&send, fId);
			if (msg->HasString("vision:partmsg")) {
				AddSend(&send, " :");
				AddSend(&send, msg->FindString("vision:partmsg"));
			}
			AddSend(&send, endl);
		}
		ClientAgent::MessageReceived(msg);
	} break;

	default:
		ClientAgent::MessageReceived(msg);
	}
}
Example #2
0
void
NamesView::MouseDown (BPoint myPoint)
{
	int32 selected (IndexOf (myPoint));
	bool handled (false);

	if (selected < 0)
	{
		DeselectAll();
		return;
	}

	BMessage *inputMsg (Window()->CurrentMessage());
	int32 mousebuttons (0),
				keymodifiers (0),
				mouseclicks (0);

	inputMsg->FindInt32 ("buttons", &mousebuttons);
	inputMsg->FindInt32 ("modifiers", &keymodifiers);
	inputMsg->FindInt32 ("clicks",	&mouseclicks);

	if (mouseclicks > 1
	&& CurrentSelection(1) <= 0
	&&	mousebuttons == B_PRIMARY_MOUSE_BUTTON
	&& (keymodifiers & B_SHIFT_KEY)	 == 0
	&& (keymodifiers & B_OPTION_KEY)	== 0
	&& (keymodifiers & B_COMMAND_KEY) == 0
	&& (keymodifiers & B_CONTROL_KEY) == 0)
	{
		// user double clicked

		BListItem *item (ItemAt (IndexOf(myPoint)));
		if (item && !item->IsSelected())
		{
			// "double" clicked away from another selection
			Select (IndexOf (myPoint), false);
			fCurrentindex = IndexOf (myPoint);
			fTracking = true;
		}
		else if (item && item->IsSelected())
		{
			// double clicking on a single item
			NameItem *myItem (reinterpret_cast<NameItem *>(item));
			BString theNick (myItem->Name());
			BMessage msg (M_OPEN_MSGAGENT);

			msg.AddString ("nick", theNick.String());
			reinterpret_cast<ChannelAgent *>(Parent()->Parent())->fMsgr.SendMessage (&msg);
		}

		handled = true;
	}

	if (mouseclicks == 1
	&&	CurrentSelection(1) <= 0
	&&	mousebuttons == B_PRIMARY_MOUSE_BUTTON
	&& (keymodifiers & B_SHIFT_KEY)	 == 0
	&& (keymodifiers & B_OPTION_KEY)	== 0
	&& (keymodifiers & B_COMMAND_KEY) == 0
	&& (keymodifiers & B_CONTROL_KEY) == 0)
	{
		// user single clicks
		BListItem *item (ItemAt (IndexOf(myPoint)));
		if (item && !item->IsSelected())
			Select (IndexOf (myPoint), false);

		fTracking = true;
		fCurrentindex = IndexOf (myPoint);
		handled = true;
	}

	if (mouseclicks >= 1
	&&	CurrentSelection(1) >= 0
	&&	mousebuttons == B_PRIMARY_MOUSE_BUTTON
	&& (keymodifiers & B_SHIFT_KEY)	 == 0
	&& (keymodifiers & B_OPTION_KEY)	== 0
	&& (keymodifiers & B_COMMAND_KEY) == 0
	&& (keymodifiers & B_CONTROL_KEY) == 0)
	{
		// user clicks on something in the middle of a sweep selection
		BListItem *item (ItemAt (IndexOf(myPoint)));
		if (item)
			Select (IndexOf (myPoint), false);

		fTracking = true;
		fCurrentindex = IndexOf (myPoint);
		handled = true;
	}

	if (mousebuttons == B_SECONDARY_MOUSE_BUTTON
	&& (keymodifiers & B_SHIFT_KEY)	 == 0
	&& (keymodifiers & B_OPTION_KEY)	== 0
	&& (keymodifiers & B_COMMAND_KEY) == 0
	&& (keymodifiers & B_CONTROL_KEY) == 0)
	{
		// user right clicks - display popup menu
		BListItem *item (ItemAt (IndexOf(myPoint)));
		if (item && !item->IsSelected())
			Select (IndexOf (myPoint), false);

		fMyPopUp->Go (
			ConvertToScreen (myPoint),
			true,
			false,
			ConvertToScreen (ItemFrame (selected)));
		handled = true;
	}
	if (mousebuttons == B_TERTIARY_MOUSE_BUTTON)
		BListView::MouseDown (myPoint);

	fLastSelected = selected;
	if (!handled)
		BListView::MouseDown (myPoint);
}
Example #3
0
void
NamesView::MessageReceived (BMessage *msg)
{
	switch (msg->what)
	{
		case M_THEME_FOREGROUND_CHANGE:
		{
			int16 which (msg->FindInt16 ("which"));
			bool refresh (false);
			switch (which)
			{
				case C_NAMES_BACKGROUND:
					fActiveTheme->ReadLock();
					SetViewColor (fActiveTheme->ForegroundAt (C_NAMES_BACKGROUND));
					refresh = true;
					fActiveTheme->ReadUnlock();
					break;

				case C_OP:
				case C_VOICE:
				case C_HELPER:
				case C_NAMES_SELECTION:
					refresh = true;
					break;

				default:
					break;
			}
			if (refresh)
				Invalidate();
		}
		break;

		case M_THEME_FONT_CHANGE:
		{
			int16 which (msg->FindInt16 ("which"));
			if (which == F_NAMES)
			{
				fActiveTheme->ReadLock();
				BFont newFont (fActiveTheme->FontAt (F_NAMES));
				fActiveTheme->ReadUnlock();
				SetFont (&newFont);
				for (int32 i = 0; i < CountItems(); i++)
					ItemAt(i)->Update(this, &newFont);
				Invalidate();
			}
		}
		break;

		case B_SIMPLE_DATA:
		{
			if (msg->HasRef("refs"))
			{
				// this only grabs the first ref for now
				// TODO: maybe implement queueing of multiple sends next time
				entry_ref ref;
				msg->FindRef("refs", &ref);
				BDirectory dir (&ref);
				// don't try to dcc send a dir
				if (dir.InitCheck() == B_OK)
					break;
				int32 idx (CurrentSelection());
				if (idx >= 0)
				{
					NameItem *item (dynamic_cast<NameItem *>(ItemAt(idx)));
					BMessage message (M_CHOSE_FILE);
					message.AddString ("nick", item->Name());
					message.AddRef ("refs", &ref);
					ClientAgent *myParent (dynamic_cast<ClientAgent *>(Parent()->Parent()));
					if (myParent)
						myParent->fSMsgr.SendMessage (&message);
				}
			}
		}
		break;

		default:
		{
			BListView::MessageReceived (msg);
		}
		break;
	}
}
Example #4
0
bool
ClientWindow::ParseCmd (const char *data)
{
	BString firstWord (GetWord(data, 1).ToUpper());
		


	if (firstWord == "/WALLOPS"	// we need to insert a ':' before parm2
	||  firstWord == "/SQUIT"   // for the user
	||  firstWord == "/PRIVMSG")
	{
		BString theCmd (firstWord.RemoveAll ("/")),
	            theRest (RestOfString (data, 2));
		
		BMessage send (M_SERVER_SEND);
		AddSend (&send, theCmd);
		if (theRest != "-9z99")
		{
			AddSend (&send, " :");
			AddSend (&send, theRest);
		}
		AddSend (&send, endl);	

		return true;
	}

	if (firstWord == "/KILL")	// we need to insert a ':' before parm3
	{                           // for the user
		BString theCmd (firstWord.RemoveAll ("/")),
				theTarget (GetWord (data, 2)),
	            theRest (RestOfString (data, 3));
		
		BMessage send (M_SERVER_SEND);		
		AddSend (&send, theCmd);
		AddSend (&send, " ");
		AddSend (&send, theTarget);
		if (theRest != "-9z99")
		{
			AddSend (&send, " :");
			AddSend (&send, theRest);
		}
		AddSend (&send, endl);	

		return true;
	}


	// some quick aliases for scripts, these will of course be
	// moved to an aliases section eventually
	
	if (firstWord == "/SOUNDPLAY"
	||  firstWord == "/CL-AMP")
	{
		app_info ai;
		be_app->GetAppInfo (&ai);
		
		BEntry entry (&ai.ref);
		BPath path;
		entry.GetPath (&path);
		path.GetParent (&path);
		//path.Append ("data");
		path.Append ("scripts");
		
		if (firstWord == "/SOUNDPLAY")
			path.Append ("soundplay-hey");
		else
			path.Append ("cl-amp-clr");
		
		BMessage *msg (new BMessage);
		msg->AddString ("exec", path.Path());
		msg->AddPointer ("client", this);
		
		thread_id execThread = spawn_thread (
			ExecPipe,
			"exec_thread",
			B_LOW_PRIORITY,
			msg);

		resume_thread (execThread);
	
		return true;
	}
		


	if (firstWord == "/ABOUT")
	{
		be_app_messenger.SendMessage (B_ABOUT_REQUESTED);
		
		return true;
	}
	
	
	if (firstWord == "/AWAY")
	{
		BString theReason (RestOfString (data, 2));
		BString tempString;
	
	
		if (theReason != "-9z99")
		{
			//nothing to do
		}
		else
		{
			theReason = "BRB"; // Todo: make a default away msg option
		}
	
		const char *expansions[1];
		expansions[0] = theReason.String();
		
		tempString = ExpandKeyed (bowser_app->GetCommand (CMD_AWAY).String(), "R",
			expansions);
		tempString.RemoveFirst("\n");
	
		BMessage send (M_SERVER_SEND);
		AddSend (&send, "AWAY");
		AddSend (&send, " :");
		AddSend (&send, theReason.String());
		AddSend (&send, endl);
		
		if (id != serverName)
		{
			ActionMessage (tempString.String(), myNick.String());
		}
		
		return true;	
	}
	
	
	if (firstWord == "/BACK")
	{
		BMessage send (M_SERVER_SEND);
	
		AddSend (&send, "AWAY");
		AddSend (&send, endl);
	
		if (id != serverName)
		{
			ActionMessage (
				bowser_app->GetCommand (CMD_BACK).String(),
				myNick.String());
		}
		
		return true;
	}
	
	
	if (firstWord == "/CHANSERV"
	||  firstWord == "/NICKSERV"
	||  firstWord == "/MEMOSERV")
	{
		BString theCmd (firstWord.RemoveFirst ("/")),
				theRest (RestOfString (data, 2));
		theCmd.ToLower();
	
		if (theRest != "-9z99")
		{
			if (bowser_app->GetMessageOpenState())
			{
				BMessage msg (OPEN_MWINDOW);
				BMessage buffer (M_SUBMIT);
	
				buffer.AddString ("input", theRest.String());
				msg.AddMessage ("msg", &buffer);
				msg.AddString ("nick", theCmd.String());
				sMsgr.SendMessage (&msg);
			}
			else
			{
				BString tempString;
				
				tempString << "[M]-> " << theCmd << " > " << theRest << "\n";
				Display (tempString.String(), 0);
	
				BMessage send (M_SERVER_SEND);
				AddSend (&send, "PRIVMSG ");
				AddSend (&send, theCmd);
				AddSend (&send, " :");
				AddSend (&send, theRest);
				AddSend (&send, endl);
			}
		}
		
		return true;
	}
	
	
	if (firstWord == "/CLEAR")
	{
		text->ClearView (false);
		return true;
	}

	if (firstWord == "/FCLEAR")
	{
		text->ClearView (true);
		return true;
	}
	
	
	if (firstWord == "/CTCP")
	{
		BString theTarget (GetWord (data, 2));
		BString theAction (RestOfString (data, 3));
	
		if (theAction != "-9z99")
		{
			theAction.ToUpper();
	
			if (theAction.ICompare ("PING") == 0)
			{
				time_t now (time (0));
	
				theAction << " " << now;
			}
	
			CTCPAction (theTarget, theAction);
	
			BMessage send (M_SERVER_SEND);
			AddSend (&send, "PRIVMSG ");
			AddSend (&send, theTarget << " :\1" << theAction << "\1");
			AddSend (&send, endl);
		}
		
		return true;
	}
	
	
	if (firstWord == "/DCC")
	{
		BString secondWord (GetWord (data, 2));
		BString theNick (GetWord (data, 3));
		BString theFile (RestOfString(data, 4));
		
		if (secondWord.ICompare ("SEND") == 0
		&&  theNick != "-9z99")
		{
			BMessage *msg (new BMessage (CHOSE_FILE));
			msg->AddString ("nick", theNick.String());
			if (theFile != "-9z99")
			{	
				char filePath[B_PATH_NAME_LENGTH] = "\0";
				if (theFile.ByteAt(0) != '/')
				{
					find_directory(B_USER_DIRECTORY, 0, false, filePath, B_PATH_NAME_LENGTH);
					filePath[strlen(filePath)] = '/';
				}
				strcat(filePath, theFile.LockBuffer(0));
				theFile.UnlockBuffer();
	
				// use BPath to resolve relative pathnames, above code forces it
				// to use /boot/home as a working dir as opposed to the app path
	
				BPath sendPath(filePath, NULL, true);
				
				// the BFile is used to verify if the file exists
				// based off the documentation get_ref_for_path *should*
				// return something other than B_OK if the file doesn't exist
				// but that doesn't seem to be working correctly
				
				BFile sendFile(sendPath.Path(), B_READ_ONLY);
				
				// if the file exists, send, otherwise drop to the file panel
				
				if (sendFile.InitCheck() == B_OK)
				{
					sendFile.Unset();
					entry_ref ref;
					get_ref_for_path(sendPath.Path(), &ref);
					msg->AddRef("refs", &ref);
					sMsgr.SendMessage(msg);	
					return true;	
				}
			}
			BFilePanel *myPanel (new BFilePanel);
			BString myTitle ("Sending a file to ");
	
			myTitle.Append (theNick);
			myPanel->Window()->SetTitle (myTitle.String());
	
			myPanel->SetMessage (msg);
	
			myPanel->SetButtonLabel (B_DEFAULT_BUTTON, "Send");
			myPanel->SetTarget (sMsgr);
			myPanel->Show();
		}
		else if (secondWord.ICompare ("CHAT") == 0
		&&       theNick != "-9z99")
		{
			BMessage msg (CHAT_ACTION);
	
			msg.AddString ("nick", theNick.String());
	
			sMsgr.SendMessage (&msg);
		}
		
		return true;
	}
	
	
	if (firstWord == "/DOP" || firstWord == "/DEOP")
	{
		BString theNick (RestOfString (data, 2));

		if (theNick != "-9z99")
		{
			BMessage send (M_SERVER_SEND);
	
			AddSend (&send, "MODE ");
			AddSend (&send, id);
			AddSend (&send, " -oooo ");
			AddSend (&send, theNick);
			AddSend (&send, endl);
		}
		
		return true;
	}
	
	
	if (firstWord == "/DESCRIBE")
	{
    	BString theTarget (GetWord (data, 2));
		BString theAction (RestOfString (data, 3));
		
		if (theAction != "-9z99") {
		
			BMessage send (M_SERVER_SEND);
	
			AddSend (&send, "PRIVMSG ");
			AddSend (&send, theTarget);
			AddSend (&send, " :\1ACTION ");
			AddSend (&send, theAction);
			AddSend (&send, "\1");
			AddSend (&send, endl);
		
			BString theActionMessage ("[ACTION]-> ");
			theActionMessage << theTarget << " -> " << theAction << "\n";
	
			Display (theActionMessage.String(), 0);
		}
		
		return true;
	}
		
	
	if (firstWord == "/DNS")
	{
		BString parms (GetWord(data, 2));
	
		ChannelWindow *window;
		MessageWindow *message;
		
		if ((window = dynamic_cast<ChannelWindow *>(this)))
		{
				int32 count (window->namesList->CountItems());
				
				for (int32 i = 0; i < count; ++i)
				{
					NameItem *item ((NameItem *)(window->namesList->ItemAt (i)));
					
					if (!item->Name().ICompare (parms.String(), strlen (parms.String()))) //nick
					{
						BMessage send (M_SERVER_SEND);
						AddSend (&send, "USERHOST ");
						AddSend (&send, item->Name().String());
						AddSend (&send, endl);
						PostMessage(&send);	
						return true;				
					}
				}
		}
	
		else if ((message = dynamic_cast<MessageWindow *>(this)))
		{
			BString eid (id);
			eid.RemoveLast (" [DCC]");
			if (!ICompare(eid, parms) || !ICompare(myNick, parms))
			{
				BMessage send (M_SERVER_SEND);
				AddSend (&send, "USERHOST ");
				AddSend (&send, parms.String());
				AddSend (&send, endl);
				PostMessage(&send);
				return true;
			}
		}
			
		if (parms != "-9z99")
		{
			BMessage *msg (new BMessage);
			msg->AddString ("lookup", parms.String());
			msg->AddPointer ("client", this);
			
			thread_id lookupThread = spawn_thread (
				DNSLookup,
				"dns_lookup",
				B_LOW_PRIORITY,
				msg);
	
			resume_thread (lookupThread);
		}
		
		return true;
	}
	
	
	if (firstWord == "/PEXEC") // piped exec
	{
		
		BString theCmd (RestOfString (data, 2));
		
		if (theCmd != "-9z99")
		{
			BMessage *msg (new BMessage);
			msg->AddString ("exec", theCmd.String());
			msg->AddPointer ("client", this);
			
			thread_id execThread = spawn_thread (
				ExecPipe,
				"exec_thread",
				B_LOW_PRIORITY,
				msg);
	
			resume_thread (execThread);
		
		}
		
		return true;
	
	}
	
	
	if (firstWord == "/EXCLUDE")
	{
		BString second (GetWord (data, 2)),
			rest (RestOfString (data, 3));
	
		if (rest != "-9z99" && rest != "-9z99")
		{
			BMessage msg (M_EXCLUDE_COMMAND);
	
			msg.AddString ("second", second.String());
			msg.AddString ("cmd", rest.String());
			msg.AddString ("server", serverName.String());
			msg.AddRect ("frame", Frame());
			bowser_app->PostMessage (&msg);	
		}
		
		return true;
	}
	
	
	if (firstWord == "/IGNORE")
	{
		BString rest (RestOfString (data, 2));
	
		if (rest != "-9z99")
		{
			BMessage msg (M_IGNORE_COMMAND);
	
			msg.AddString ("cmd", rest.String());
			msg.AddString ("server", serverName.String());
			msg.AddRect ("frame", Frame());
			bowser_app->PostMessage (&msg);
		}
		
		return true;
	}	
	
	if (firstWord == "/INVITE" || firstWord == "/I")
	{

		BString theUser (GetWord (data, 2));

		if (theUser != "-9z99")
		{
			BString theChan (GetWord (data, 3));
	
			if (theChan == "-9z99")
				theChan = id;
	
			BMessage send (M_SERVER_SEND);
	
			AddSend (&send, "INVITE ");
			AddSend (&send, theUser << " " << theChan);
			AddSend (&send, endl);
		}
		
		return true;	
	}
	
	
	if (firstWord == "/JOIN" || firstWord == "/J")
	{
		BString channel (GetWord (data, 2));

		if (channel != "-9z99")
		{
			if (channel[0] != '#' && channel[0] != '&')
				channel.Prepend("#");

			BMessage send (M_SERVER_SEND);

			AddSend (&send, "JOIN ");
			AddSend (&send, channel);

			BString key (GetWord (data, 3));
			if (key != "-9z99")
			{
				AddSend (&send, " ");
				AddSend (&send, key);
			}
	
			AddSend (&send, endl);
		}
		
		return true;
	}
	
	if (firstWord == "/KICK" || firstWord == "/K")
	{
		BString theNick (GetWord (data, 2));
	
		if (theNick != "-9z99")
		{
			BString theReason (RestOfString (data, 3));
	
			if (theReason == "-9z99")
			{
				// No expansions
				theReason = bowser_app
					->GetCommand (CMD_KICK);
			}
	
			BMessage send (M_SERVER_SEND);
	
			AddSend (&send, "KICK ");
			AddSend (&send, id);
			AddSend (&send, " ");
			AddSend (&send, theNick);
			AddSend (&send, " :");
			AddSend (&send, theReason);
			AddSend (&send, endl);
		}
		
		return true;
	}
	
	
	if (firstWord == "/LIST")
	{
		BMessage msg (M_LIST_COMMAND);

		msg.AddString ("cmd", data);
		msg.AddString ("server", serverName.String());
		msg.AddRect ("frame", Frame());
		bowser_app->PostMessage (&msg);
	
		return true;
	}
	
	
	if (firstWord == "/M")
	{
		BString theMode (RestOfString (data, 2));
		
		BMessage send (M_SERVER_SEND);
		AddSend (&send, "MODE ");
	
		if (id == serverName)
			AddSend (&send, myNick);
		else if (id[0] == '#' || id[0] == '&')
			AddSend (&send, id);
		else
			AddSend (&send, myNick);
		 
		if (theMode != "-9z99")
		{
				AddSend (&send, " ");
				AddSend (&send, theMode);
		}

		AddSend (&send, endl);
	
		return true;
	}
	
	
	if (firstWord == "/ME")
	{
		BString theAction (RestOfString (data, 2));

		if (theAction != "-9z99")
		{
			ActionMessage (theAction.String(), myNick.String());
		}
		
		return true;
	}

		
	if (firstWord == "/MODE")
	{
		BString theMode (RestOfString (data, 3));
		BString theTarget (GetWord (data, 2));

		if (theTarget != "-9z99")
		{
			BMessage send (M_SERVER_SEND);
	
			AddSend (&send, "MODE ");
	
			if (theMode == "-9z99")
				AddSend (&send, theTarget);
			else
				AddSend (&send, theTarget << " " << theMode);
	
			AddSend (&send, endl);
		}
		
		return true;
	}
	
	
	if (firstWord == "/MSG")
	{
		BString theRest (RestOfString (data, 3));
		BString theNick (GetWord (data, 2));
	
		if (theRest != "-9z99"
		&&  myNick.ICompare (theNick))
		{
			if (bowser_app->GetMessageOpenState())
			{
				BMessage msg (OPEN_MWINDOW);
				BMessage buffer (M_SUBMIT);
	
				buffer.AddString ("input", theRest.String());
				msg.AddMessage ("msg", &buffer);
				msg.AddString ("nick", theNick.String());
				sMsgr.SendMessage (&msg);
			}
			else
			{
				BString tempString;
				
				tempString << "[M]-> " << theNick << " > " << theRest << "\n";
				Display (tempString.String(), 0);
	
				BMessage send (M_SERVER_SEND);
				AddSend (&send, "PRIVMSG ");
				AddSend (&send, theNick);
				AddSend (&send, " :");
				AddSend (&send, theRest);
				AddSend (&send, endl);
			}

		}
		return true;
	}	
		
	if (firstWord == "/NICK")
	{
		BString newNick (GetWord (data, 2));

		if (newNick != "-9z99")
		{
			BString tempString ("*** Trying new nick ");
	
			tempString << newNick << ".\n";
			Display (tempString.String(), 0);
	
			BMessage send (M_SERVER_SEND);
			AddSend (&send, "NICK ");
			AddSend (&send, newNick);
			AddSend (&send, endl);
		}
		
		return true;
	}
	
	
	if (firstWord == "/NOTICE")
	{
		BString theTarget (GetWord (data, 2));
		BString theMsg (RestOfString (data, 3));
	
		if (theMsg != "-9z99")
		{
			BMessage send (M_SERVER_SEND);
	
			AddSend (&send, "NOTICE ");
			AddSend (&send, theTarget);
			AddSend (&send, " :");
			AddSend (&send, theMsg);
			AddSend (&send, endl);
	
			BString tempString ("[N]-> ");
			tempString << theTarget << " -> " << theMsg << '\n';
	
			Display (tempString.String(), 0);
		}
		
		return true;
	}
	
	
	if (firstWord == "/NOTIFY")
	{
		BString rest (RestOfString (data, 2));
	
		if (rest != "-9z99")
		{
			BMessage msg (M_NOTIFY_COMMAND);
	
			msg.AddString ("cmd", rest.String());
			msg.AddBool ("add", true);
			msg.AddString ("server", serverName.String());
			msg.AddRect ("frame", Frame());
			bowser_app->PostMessage (&msg);
		}
		
		return true;
	}

	if (firstWord == "/OP")
	{
		BString theNick (RestOfString (data, 2));
	
		if (theNick != "-9z99")
		{
			// TODO only applies to a channel
	
			BMessage send (M_SERVER_SEND);
	
			AddSend (&send, "MODE ");
			AddSend (&send, id);
			AddSend (&send, " +oooo ");
			AddSend (&send, theNick);
			AddSend (&send, endl);
		}
		
		return true;
	}
	

	if (firstWord == "/PART")
	{
		BMessage msg (B_QUIT_REQUESTED);

		msg.AddBool ("bowser:part", true);
		PostMessage (&msg);

		return true;
	}	
	
	
	if (firstWord == "/PING")
	{
		BString theNick (GetWord (data, 2));
	
		if (theNick != "-9z99")
		{
			long theTime (time (0));
			BString tempString ("/CTCP ");
	
			tempString << theNick << " PING " << theTime;
			SlashParser (tempString.String());
		}
	
		return true;
	}
	
	
	if (firstWord == "/PREFERENCES")
	{
		be_app_messenger.SendMessage (M_PREFS_BUTTON);
		
		return true;
	}
	
	
	if (firstWord == "/QUERY" || firstWord == "/Q")
	{
		BString theNick (GetWord (data, 2));

		if (theNick != "-9z99")
		{
			BMessage msg (OPEN_MWINDOW);
	
			msg.AddString ("nick", theNick.String());
			sMsgr.SendMessage (&msg);
		}
	
		return true;	
	}

	
	if (firstWord == "/QUIT")
	{
		BString theRest (RestOfString (data, 2));
		BString buffer;
	
		if (theRest == "-9z99")
		{
			const char *expansions[1];
			BString version (bowser_app->BowserVersion());
	
			expansions[0] = version.String();
			theRest = ExpandKeyed (bowser_app
				->GetCommand (CMD_QUIT).String(), "V", expansions);
		}
	
		buffer << "QUIT :" << theRest;
	
		BMessage msg (B_QUIT_REQUESTED);
		msg.AddString ("bowser:quit", buffer.String());
		sMsgr.SendMessage (&msg);
	
		return true;
	}
	
	
	if (firstWord == "/RAW" || firstWord == "/QUOTE")
	{

		BString theRaw (RestOfString (data, 2));
	
		if (theRaw != "-9z99")
		{
			BMessage send (M_SERVER_SEND);
	
			AddSend (&send, theRaw);
			AddSend (&send, endl);
	
			BString tempString ("[R]-> ");
			tempString << theRaw << '\n';
	
			Display (tempString.String(), 0);
	
		}
		
		return true;
	}
	
	
	if (firstWord == "/RECONNECT")
	{
		BMessage msg (M_SLASH_RECONNECT);
		msg.AddString ("server", serverName.String());
		bowser_app->PostMessage (&msg);
		return true;
	}
	
	
	if (firstWord == "/SLEEP")
	{
		BString rest (RestOfString (data, 2));
	
		if (rest != "-9z99")
		{
			// this basically locks up the window its run from,
			// but I can't think of a better way with our current
			// commands implementation
			int32 time = atoi(rest.String());
			snooze(time * 1000 * 100); // deciseconds? 10 = one second
		}
		
		return true;
	
	}
	
		
	if (firstWord == "/TOPIC" || firstWord == "/T")
	{
		BString theChan (id);
		BString theTopic (RestOfString (data, 2));
		BMessage send (M_SERVER_SEND);
	
		AddSend (&send, "TOPIC ");
	
		if (theTopic == "-9z99")
			AddSend (&send, theChan);
		else
			AddSend (&send, theChan << " :" << theTopic);
		AddSend (&send, endl);
		
		return true;
	}
	
	
	if (firstWord == "/UNIGNORE")
	{
		BString rest (RestOfString (data, 2));
	
		if (rest != "-9z99")
		{
			BMessage msg (M_UNIGNORE_COMMAND);
	
			msg.AddString ("cmd", rest.String());
			msg.AddString ("server", serverName.String());
			msg.AddRect ("frame", Frame());
			bowser_app->PostMessage (&msg);
		}
	
		return true;
	}
	
	
	if (firstWord == "/UNNOTIFY")
	{
		BString rest (RestOfString (data, 2));
	
		if (rest != "-9z99")
		{
			BMessage msg (M_NOTIFY_COMMAND);
	
			msg.AddString ("cmd", rest.String());
			msg.AddBool ("add", false);
			msg.AddRect ("frame", Frame());
			msg.AddString ("server", serverName.String());
			bowser_app->PostMessage (&msg);
		}
	
		return true;
	}
	
	
	if (firstWord == "/UPTIME")
	{
		BString parms (GetWord(data, 2));
		
		BString uptime (DurationString(system_time()));
		BString expandedString;
		const char *expansions[1];
		expansions[0] = uptime.String();
		expandedString = ExpandKeyed (bowser_app->GetCommand (CMD_UPTIME).String(), "U",
			expansions);
		expandedString.RemoveFirst("\n");
	
		if ((id != serverName) && (parms == "-9z99"))
		{
			BMessage send (M_SERVER_SEND);
			
			AddSend (&send, "PRIVMSG ");
			AddSend (&send, id);
			AddSend (&send, " :");
			AddSend (&send, expandedString.String());
			AddSend (&send, endl);
			
			ChannelMessage (expandedString.String(), myNick.String());
		}
		else if ((parms == "-l") || (id == serverName)) // echo locally
		{
			BString tempString;
				
			tempString << "Uptime: " << expandedString << "\n";
			Display (tempString.String(), &whoisColor);
			
		}
		
		return true;
	}
	
	
	if (firstWord == "/VERSION"
	||  firstWord == "/TIME")
	{
		BString theCmd (firstWord.RemoveFirst ("/")),
				theNick (GetWord (data, 2));
		theCmd.ToUpper();
	
		// the "." check is because the user might specify a server name
		
		if (theNick != "-9z99" && theNick.FindFirst(".") < 0)
		{
			BString tempString ("/CTCP ");
	
			tempString << theNick << " " << theCmd;
			SlashParser (tempString.String());
		}
		else
		{
		  	BMessage send (M_SERVER_SEND);
	
			AddSend (&send, theCmd);
			
			if (theNick != "-9z99")
			{
				AddSend (&send, " ");
				AddSend (&send, theNick);
			}
						
			AddSend (&send, endl);
		}
		
		return true;
	}
	
	
	if (firstWord == "/VISIT")
	{
		BString buffer (data);
		int32 place;
	
		if ((place = buffer.FindFirst (" ")) >= 0)
		{
			buffer.Remove (0, place + 1);
	
			const char *arguments[] = {buffer.String(), 0};
			
			
	
			be_roster->Launch (
				"text/html",
				1,
				const_cast<char **>(arguments));
		}
		
		return true;
	}



	if (firstWord != "" && firstWord[0] == '/')
	// != "" is required to prevent a nasty crash with string[0]
	{
		BString theCmd (firstWord.RemoveAll ("/")),
	            theRest (RestOfString (data, 2));
		
		BMessage send (M_SERVER_SEND);
		
		if (theCmd == "W")
			theCmd = "WHOIS";

		AddSend (&send, theCmd);
	
		if (theRest != "-9z99")
		{
			AddSend (&send, " ");
			AddSend (&send, theRest);
		}
		AddSend (&send, endl);	

		return true;
	}
	
	return false;  // we couldn't handle this message

}