int CBouquetList::doMenu()
{
	int i = 0, ret = 0;
	int select = -1;
	static int old_selected = 0;
	signed int bouquet_id;
	char cnt[5];
	CZapitBouquet * tmp, * zapitBouquet;
	ZapitChannelList* channels;

	if(Bouquets.empty() || g_settings.minimode)
		return 0;

	zapitBouquet = Bouquets[selected]->zapitBouquet;
	/* zapitBouquet not NULL only on real bouquets, satellitePosition is set for providers or SAT */
	if(!zapitBouquet && Bouquets[selected]->satellitePosition == INVALID_SAT_POSITION)
		return 0;

	CMenuWidget* menu = new CMenuWidget(LOCALE_CHANNELLIST_EDIT, NEUTRINO_ICON_SETTINGS);
	menu->enableFade(false);
	menu->enableSaveScreen(true);
	CMenuSelectorTarget * selector = new CMenuSelectorTarget(&select);

	int old_epg = zapitBouquet ? zapitBouquet->bScanEpg : 0;
	int old_ci = zapitBouquet ? zapitBouquet->bUseCI : 0;
	sprintf(cnt, "%d", i);
	/* FIXME menu centered different than bouquet list ??? */
	/* provider bouquet */
	if (zapitBouquet && !zapitBouquet->bUser) {
		menu->addItem(new CMenuForwarder(LOCALE_FAVORITES_COPY, true, NULL, selector, cnt, CRCInput::RC_blue), old_selected == i ++);
		if (!zapitBouquet->bWebtv && g_settings.epg_scan == CEpgScan::SCAN_SEL)
			menu->addItem(new CMenuOptionChooser(LOCALE_MISCSETTINGS_EPG_SCAN, &zapitBouquet->bScanEpg, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true));
		if (!zapitBouquet->bWebtv)
			menu->addItem(new CMenuOptionChooser(LOCALE_CI_USE, &zapitBouquet->bUseCI, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true));
		menu->exec(NULL, "");
		delete menu;
		delete selector;
		printf("CBouquetList::doMenu: %d selected\n", select);
		if (old_epg != zapitBouquet->bScanEpg) {
			save_bouquets = true;
			CNeutrinoApp::getInstance()->MarkBouquetsChanged();
			ret = -1;
		}
		if (old_ci != zapitBouquet->bUseCI) {
			channels = &zapitBouquet->tvChannels;
			for(int li = 0; li < (int) channels->size(); li++)
				(*channels)[li]->bUseCI = zapitBouquet->bUseCI;

			channels = &zapitBouquet->radioChannels;
			for(int li = 0; li < (int) channels->size(); li++)
				(*channels)[li]->bUseCI = zapitBouquet->bUseCI;

			CServiceManager::getInstance()->SetCIFilter();
			save_bouquets = true;
			CNeutrinoApp::getInstance()->MarkBouquetsChanged();
			ret = -1;
		}

		if(select >= 0) {
			bool added = false;
			old_selected = select;
			switch(select) {
				case 0: // copy to favorites
					hide();
					bouquet_id = g_bouquetManager->existsUBouquet(Bouquets[selected]->channelList->getName());
					if(bouquet_id < 0) {
						tmp = g_bouquetManager->addBouquet(Bouquets[selected]->channelList->getName(), true);
						bouquet_id = g_bouquetManager->existsUBouquet(Bouquets[selected]->channelList->getName());
					} else
						tmp = g_bouquetManager->Bouquets[bouquet_id];

					if(bouquet_id < 0)
						return 0;

					channels = &zapitBouquet->tvChannels;
					for(int li = 0; li < (int) channels->size(); li++) {
						if (!g_bouquetManager->existsChannelInBouquet(bouquet_id, ((*channels)[li])->getChannelID())) {
							added = true;
							tmp->addService((*channels)[li]);
						}
					}
					channels = &zapitBouquet->radioChannels;
					for(int li = 0; li < (int) channels->size(); li++) {
						if (!g_bouquetManager->existsChannelInBouquet(bouquet_id, ((*channels)[li])->getChannelID())) {
							added = true;
							tmp->addService((*channels)[li]);
						}
					}
					if (added) {
						CNeutrinoApp::getInstance()->MarkFavoritesChanged();
						CNeutrinoApp::getInstance()->MarkChannelsInit();
						return 1;
					}
					break;
				default:
					break;
			}
		}
	} else {
		/* user or satellite bouquet */
		menu->addItem(new CMenuForwarder(LOCALE_BOUQUETEDITOR_DELETE, true, NULL, selector, cnt, CRCInput::RC_red), old_selected == i ++);
		if (zapitBouquet && !zapitBouquet->bWebtv && (g_settings.epg_scan == CEpgScan::SCAN_SEL))
			menu->addItem(new CMenuOptionChooser(LOCALE_MISCSETTINGS_EPG_SCAN, &zapitBouquet->bScanEpg, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true));
		if (zapitBouquet && !zapitBouquet->bWebtv)
			menu->addItem(new CMenuOptionChooser(LOCALE_CI_USE, &zapitBouquet->bUseCI, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true));

		menu->exec(NULL, "");
		delete menu;
		delete selector;
		if (zapitBouquet && (old_epg != zapitBouquet->bScanEpg)) {
			save_bouquets = true;
			CNeutrinoApp::getInstance()->MarkFavoritesChanged();
			ret = -1;
		}
		if (zapitBouquet && (old_ci != zapitBouquet->bUseCI)) {
			channels = &zapitBouquet->tvChannels;
			for(int li = 0; li < (int) channels->size(); li++)
				(*channels)[li]->bUseCI = zapitBouquet->bUseCI;

			channels = &zapitBouquet->radioChannels;
			for(int li = 0; li < (int) channels->size(); li++)
				(*channels)[li]->bUseCI = zapitBouquet->bUseCI;

			CServiceManager::getInstance()->SetCIFilter();
			save_bouquets = true;
			CNeutrinoApp::getInstance()->MarkFavoritesChanged();
			ret = -1;
		}

		printf("CBouquetList::doMenu: %d selected\n", select);
		if(select >= 0) {
			old_selected = select;

			int result = ShowMsg ( LOCALE_BOUQUETEDITOR_DELETE, Bouquets[selected]->channelList->getName(), CMessageBox::mbrNo, CMessageBox::mbYes | CMessageBox::mbNo );
			if(result != CMessageBox::mbrYes)
				return 0;

			if (zapitBouquet) {
				bouquet_id = g_bouquetManager->existsUBouquet(Bouquets[selected]->channelList->getName());
				if(bouquet_id >= 0) {
					g_bouquetManager->deleteBouquet(bouquet_id);
					CNeutrinoApp::getInstance()->MarkFavoritesChanged();
					CNeutrinoApp::getInstance()->MarkChannelsInit();
					return 1;
				}
			} else {
				CServiceManager::getInstance()->RemovePosition(Bouquets[selected]->satellitePosition);
				g_bouquetManager->loadBouquets();
				g_bouquetManager->deletePosition(Bouquets[selected]->satellitePosition);
				CNeutrinoApp::getInstance()->MarkChannelsChanged();
				CNeutrinoApp::getInstance()->MarkBouquetsChanged();
				CNeutrinoApp::getInstance()->MarkChannelsInit();
				return 1;
			}
		}
	}
	return ret;
}
int CCAMMenuHandler::handleCamMsg(const neutrino_msg_t msg, neutrino_msg_data_t data, int &msgret, bool from_menu)
{
	char str[255];
	char cnt[5];
	int i;
	MMI_MENU_LIST_INFO Menu;
	MMI_ENQUIRY_INFO MmiEnquiry;
	MMI_MENU_LIST_INFO *pMenu = &Menu;
	MMI_ENQUIRY_INFO *pMmiEnquiry = &MmiEnquiry;
	CA_MESSAGE Msg, *rMsg;

	//printf("CCAMMenuHandler::handleCamMsg: msg %x data %x from %s\n", msg, data, from_menu ? "menu" : "neutrino");
	msgret = messages_return::unhandled;

	if ((msg == NeutrinoMessages::EVT_TIMER) && (data == close_timer)) {
		printf("CCAMMenuHandler::handleCamMsg: EVT_TIMER close_timer %d\n", close_timer);
		g_RCInput->killTimer(close_timer);
		msgret = messages_return::cancel_info;
	}

	if (msg != NeutrinoMessages::EVT_CA_MESSAGE)
		return 1;

	msgret = messages_return::handled;

	rMsg	= (CA_MESSAGE *)data;
	if (!rMsg)
		return -1;

	Msg = *rMsg;
	delete rMsg;

	u32 MsgId             = Msg.MsgId;
	CA_SLOT_TYPE SlotType = Msg.SlotType;
	int curslot           = Msg.Slot;

	printf("CCAMMenuHandler::handleCamMsg: CA msg %x from %s\n", MsgId, from_menu ? "menu" : "neutrino");

	if (g_settings.ci_ignore_messages && !from_menu)
		return 1;

	hideHintBox();

	if (SlotType != CA_SLOT_TYPE_SMARTCARD && SlotType != CA_SLOT_TYPE_CI)
		return -1;

	if(MsgId == CA_MESSAGE_MSG_INSERTED) {
		snprintf(str, sizeof(str), "%s %d", 
				g_Locale->getText(SlotType == CA_SLOT_TYPE_CI ? LOCALE_CI_INSERTED : LOCALE_SC_INSERTED), (int)curslot+1);
		printf("CCAMMenuHandler::handleCamMsg: %s\n", str);
		ShowHint(LOCALE_MESSAGEBOX_INFO, str, 450, 3);
		if (in_menu)
			msgret = messages_return::cancel_all;
	} else if (MsgId == CA_MESSAGE_MSG_REMOVED) {
		snprintf(str, sizeof(str), "%s %d", 
				g_Locale->getText(SlotType == CA_SLOT_TYPE_CI ? LOCALE_CI_REMOVED : LOCALE_SC_REMOVED), (int)curslot+1);

		printf("CCAMMenuHandler::handleCamMsg: %s\n", str);
		ShowHint(LOCALE_MESSAGEBOX_INFO, str, 450, 3);
#if 0
		if (menu_slot == curslot && menu_type == SlotType)
			return 3;
#endif
		if (in_menu)
			msgret = messages_return::cancel_all;
	} else if(MsgId == CA_MESSAGE_MSG_INIT_OK) {
		char name[255] = "Unknown";
		if (ca)
			ca->ModuleName(SlotType, curslot, name);

		snprintf(str, sizeof(str), "%s %d: %s", 
				g_Locale->getText(SlotType == CA_SLOT_TYPE_CI ? LOCALE_CI_INIT_OK : LOCALE_SC_INIT_OK), (int)curslot+1, name);
		printf("CCAMMenuHandler::handleCamMsg: %s\n", str);
		CCamManager::getInstance()->Start(CZapit::getInstance()->GetCurrentChannelID(), CCamManager::PLAY, true);
		ShowHint(LOCALE_MESSAGEBOX_INFO, str, 450, 3);
	} else if(MsgId == CA_MESSAGE_MSG_INIT_FAILED) {
		char name[255] = "Unknown";
		if (ca)
			ca->ModuleName(SlotType, curslot, name);

		snprintf(str, sizeof(str), "%s %d: %s", 
				g_Locale->getText(SlotType == CA_SLOT_TYPE_CI ? LOCALE_CI_INIT_FAILED : LOCALE_SC_INIT_FAILED), (int)curslot+1, name);

		printf("CCAMMenuHandler::handleCamMsg: %s\n", str);
		ShowHint(LOCALE_MESSAGEBOX_INFO, str, 450, 3);
	} else if(MsgId == CA_MESSAGE_MSG_MMI_MENU || MsgId == CA_MESSAGE_MSG_MMI_LIST) {
		bool sublevel = false;

		if(MsgId != CA_MESSAGE_MSG_MMI_MENU)
			sublevel = true;

		if (!(Msg.Flags & CA_MESSAGE_HAS_PARAM1_DATA))
			return -1;

		memmove(pMenu, (MMI_MENU_LIST_INFO*)Msg.Msg.Data[0], sizeof(MMI_MENU_LIST_INFO));
		free((void *)Msg.Msg.Data[0]);

		printf("CCAMMenuHandler::handleCamMsg: slot %d menu ready, title %s choices %d\n", curslot, convertDVBUTF8(pMenu->title, strlen(pMenu->title), 0).c_str(), pMenu->choice_nb);

		int menuret = menu_return::RETURN_REPAINT;
		int selected = -1;
		if(pMenu->choice_nb && from_menu) {
			CMenuWidget* menu = new CMenuWidget(convertDVBUTF8(pMenu->title, strlen(pMenu->title), 0).c_str(), NEUTRINO_ICON_SETTINGS);
			menu->enableSaveScreen(true);

			CMenuSelectorTarget * selector = new CMenuSelectorTarget(&selected);
			int slen = strlen(pMenu->subtitle);
			if(slen) {
				char * sptr = pMenu->subtitle;
				char * tptr = sptr;
				int bpos = 0;
				for(int li = 0; li < slen; li++) {
					if((tptr[li] == 0x8A) || ((bpos > 38) && (tptr[li] == 0x20)) ) {
						bpos = 0;
						tptr[li] = 0;
						printf("CCAMMenuHandler::handleCamMsg: subtitle: %s\n", sptr);
						menu->addItem(new CMenuForwarder(convertDVBUTF8(sptr, strlen(sptr), 0).c_str(), false));
						sptr = &tptr[li+1];
					}
					bpos++;
				}
				if(strlen(sptr)) {
					printf("CCAMMenuHandler::handleCamMsg: subtitle: %s\n", sptr);
					menu->addItem(new CMenuForwarder(convertDVBUTF8(sptr, strlen(sptr), 0).c_str(), false));
				}
			}
			for(i = 0; (i < pMenu->choice_nb) && (i < MAX_MMI_ITEMS); i++) {
				snprintf(cnt, sizeof(cnt), "%d", i);
				if(sublevel)
					menu->addItem(new CMenuForwarder(convertDVBUTF8(pMenu->choice_item[i], strlen(pMenu->choice_item[i]), 0).c_str(), true, NULL, selector, cnt));
				else
					menu->addItem(new CMenuForwarder(convertDVBUTF8(pMenu->choice_item[i], strlen(pMenu->choice_item[i]), 0).c_str(), true, NULL, selector, cnt, CRCInput::convertDigitToKey(i+1)));
			}
			slen = strlen(pMenu->bottom);
			if(slen) {
				printf("CCAMMenuHandler::handleCamMsg: bottom: %s\n", pMenu->bottom);
				menu->addItem(new CMenuForwarder(convertDVBUTF8(pMenu->bottom, slen, 0).c_str(), false));
			}

			menuret = menu->exec(NULL, "");
			delete menu;
			delete selector;
		} else {

			char lstr[255];
			int slen = 0;

			if(strlen(pMenu->title))
				slen += snprintf(&lstr[slen], 255-slen, "%s\n", pMenu->title);
			if(strlen(pMenu->subtitle))
				slen += snprintf(&lstr[slen], 255-slen, "%s\n", pMenu->subtitle);
			if(strlen(pMenu->bottom))
				slen += snprintf(&lstr[slen], 255-slen, "%s\n", pMenu->bottom);

			for(i = 0; (i < pMenu->choice_nb) && (i < MAX_MMI_ITEMS); i++)
				slen += snprintf(&lstr[slen], 255-slen, "%s\n", pMenu->choice_item[i]);

			ShowHint(LOCALE_MESSAGEBOX_INFO, convertDVBUTF8(lstr, slen, 0).c_str());
			return 0;
		}

		if(sublevel)
			return menuret == menu_return::RETURN_EXIT_ALL ? 3 : 0;

		if(selected >= 0) {
			printf("CCAMMenuHandler::handleCamMsg: selected %d:%s sublevel %s\n", selected, pMenu->choice_item[i], sublevel ? "yes" : "no");
			ca->MenuAnswer(SlotType, curslot, selected+1);
			timeoutEnd = CRCInput::calcTimeoutEnd(10);
			return 1;
		} else {
			return menuret == menu_return::RETURN_EXIT_ALL ? 3 : 2;
		}
	}
	else if(MsgId == CA_MESSAGE_MSG_MMI_REQ_INPUT) {
		if (!(Msg.Flags & CA_MESSAGE_HAS_PARAM1_DATA))
			return -1;

		memmove(pMmiEnquiry, (MMI_ENQUIRY_INFO *)Msg.Msg.Data[0], sizeof(MMI_ENQUIRY_INFO));
		free((void *)Msg.Msg.Data[0]);
		printf("CCAMMenuHandler::handleCamMsg: slot %d input request, text %s\n", curslot, convertDVBUTF8(pMmiEnquiry->enquiryText, strlen(pMmiEnquiry->enquiryText), 0).c_str());

		std::string ENQAnswer;

		if (/* !from_menu && */ g_settings.ci_save_pincode && pMmiEnquiry->blind != 0 && (int) g_settings.ci_pincode.length() == pMmiEnquiry->answerlen) {
			static int acount = 0;
			static time_t last_ask = 0;

			ENQAnswer = g_settings.ci_pincode;
			printf("CCAMMenuHandler::handleCamMsg: using saved answer [%s] (#%d, time diff %d)\n", ENQAnswer.c_str(), acount, (int) (time_monotonic() - last_ask));
			if ((time_monotonic() - last_ask) < 10) {
				acount++;
				if (acount > 4)
					g_settings.ci_pincode.clear();
			} else {
				last_ask = time_monotonic();
				acount = 0;
			}
		} else {
			CEnquiryInput *Inquiry = new CEnquiryInput((char *)convertDVBUTF8(pMmiEnquiry->enquiryText, strlen(pMmiEnquiry->enquiryText), 0).c_str(), &ENQAnswer, pMmiEnquiry->answerlen, pMmiEnquiry->blind != 0, NONEXISTANT_LOCALE);
			Inquiry->exec(NULL, "");
			delete Inquiry;
			g_settings.ci_pincode = ENQAnswer;
		}

		printf("CCAMMenuHandler::handleCamMsg: input=[%s]\n", ENQAnswer.c_str());

		if((int) ENQAnswer.length() != pMmiEnquiry->answerlen) {
			printf("CCAMMenuHandler::handleCamMsg: wrong input len\n");
			ca->InputAnswer(SlotType, curslot, (unsigned char *)ENQAnswer.c_str(), 0);
			return 1; //FIXME
		} else {
			ca->InputAnswer(SlotType, curslot, (unsigned char *)ENQAnswer.c_str(), pMmiEnquiry->answerlen);
			return 1;
		}
	}
	else if(MsgId == CA_MESSAGE_MSG_MMI_CLOSE) {
		int timeout = 0;
		if (Msg.Flags & CA_MESSAGE_HAS_PARAM1_INT)
			timeout = Msg.Msg.Param[0];
		printf("CCAMMenuHandler::handleCamMsg: close request slot: %d (timeout %d)\n", curslot, timeout);
		//ca->MenuClose(SlotType, curslot);
		if (timeout)
			close_timer = g_RCInput->addTimer(timeout*1000*1000, true);
		else
			msgret = messages_return::cancel_info;
		return 0;
	}
	else if(MsgId == CA_MESSAGE_MSG_MMI_TEXT) {
		printf("CCAMMenuHandler::handleCamMsg: text\n");
	}
	else if(MsgId == CA_MESSAGE_MSG_CHANNEL_CHANGE) {
		if (!(Msg.Flags & CA_MESSAGE_HAS_PARAM1_LONG))
			return -1;

		t_channel_id chid = Msg.Msg.ParamLong[0];
		printf("CCAMMenuHandler::handleCamMsg: CA_MESSAGE_MSG_CHANNEL_CHANGE: %" PRIx64 "\n", chid);
		CZapitChannel * channel = CServiceManager::getInstance()->FindChannel48(chid);
		if (!channel) {
			printf("CCAMMenuHandler::handleCamMsg: channel %" PRIx64 "not found\n", chid);
			return -1;
		}
		CNeutrinoApp::getInstance()->zapTo(channel->getChannelID());
	} 
	return 1;
}