extern "C" int __declspec(dllexport) Load(void)
{
	char service[100]={""};

	PROTOCOLDESCRIPTOR pd={ PROTOCOLDESCRIPTOR_V3_SIZE };

#ifdef _DEBUG
	_OutputDebugString(_T("Entering Load dll"));
#endif

	mir_getLP( &pluginInfo );
	//hCurrentEditMutex=CreateMutex(NULL,FALSE,_T("CurrentEditMutex"));
	hExceptionsMutex=CreateMutex(NULL,FALSE,_T("ExceptionsMutex"));

	LoadSettings();
	connExceptions=LoadSettingsConnections();
//create protocol
	//ZeroMemory(&pd,sizeof(pd));
	//pd.cbSize=sizeof(pd);
 	pd.szName=PLUGINNAME;
	pd.type=PROTOTYPE_PROTOCOL;
	CallService(MS_PROTO_REGISTERMODULE,0,(LPARAM)&pd);
	//set all contacts to offline

	for (HANDLE hContact = db_find_first(PLUGINNAME); hContact != NULL; hContact = db_find_next(hContact,PLUGINNAME))
		db_set_w(hContact,PLUGINNAME,"status",ID_STATUS_OFFLINE);

	mir_snprintf(service,sizeof(service), "%s%s", PLUGINNAME, PS_GETCAPS);
	CreateServiceFunction(service, GetCaps);
	mir_snprintf(service,sizeof(service), "%s%s", PLUGINNAME, PS_GETNAME);
	CreateServiceFunction(service, GetName);
	mir_snprintf(service,sizeof(service), "%s%s", PLUGINNAME, PS_LOADICON);
	CreateServiceFunction(service, TMLoadIcon);
	mir_snprintf(service,sizeof(service), "%s%s", PLUGINNAME, PS_SETSTATUS);
	CreateServiceFunction(service, SetStatus);
	mir_snprintf(service,sizeof(service), "%s%s", PLUGINNAME, PS_GETSTATUS);
	CreateServiceFunction(service, GetStatus);


	SkinAddNewSoundEx(PLUGINNAME_NEWSOUND,PLUGINNAME, LPGEN("New Connection Notification"));
	hOptInit = HookEvent(ME_OPT_INITIALISE, ConnectionNotifyOptInit);//register service to hook option call
	assert(hOptInit);
	hHookModulesLoaded = HookEvent(ME_SYSTEM_MODULESLOADED, modulesloaded);//hook event that all plugins are loaded
	assert(hHookModulesLoaded);
	hHookPreShutdown = HookEvent(ME_SYSTEM_PRESHUTDOWN, preshutdown);
	return 0;
}
extern "C" int __declspec(dllexport) Load(void)
{
#ifdef _DEBUG
	_OutputDebugString(_T("Entering Load dll"));
#endif

	mir_getLP(&pluginInfo);
	mir_getCLI();

	hExceptionsMutex = CreateMutex(NULL, FALSE, _T("ExceptionsMutex"));

	LoadSettings();
	connExceptions = LoadSettingsConnections();

	PROTOCOLDESCRIPTOR pd = { 0 };
	pd.cbSize = sizeof(pd);
	pd.szName = PLUGINNAME;
	pd.type = PROTOTYPE_PROTOCOL;
	Proto_RegisterModule(&pd);

	//set all contacts to offline
	for (MCONTACT hContact = db_find_first(PLUGINNAME); hContact != NULL; hContact = db_find_next(hContact, PLUGINNAME))
		db_set_w(hContact, PLUGINNAME, "status", ID_STATUS_OFFLINE);

	CreateProtoServiceFunction(PLUGINNAME, PS_GETCAPS, GetCaps);
	CreateProtoServiceFunction(PLUGINNAME, PS_GETNAME, GetName);
	CreateProtoServiceFunction(PLUGINNAME, PS_LOADICON, TMLoadIcon);
	CreateProtoServiceFunction(PLUGINNAME, PS_SETSTATUS, SetStatus);
	CreateProtoServiceFunction(PLUGINNAME, PS_GETSTATUS, GetStatus);

	SkinAddNewSoundEx(PLUGINNAME_NEWSOUND, PLUGINNAME, LPGEN("New Connection Notification"));
	hOptInit = HookEvent(ME_OPT_INITIALISE, ConnectionNotifyOptInit);//register service to hook option call
	assert(hOptInit);
	hHookModulesLoaded = HookEvent(ME_SYSTEM_MODULESLOADED, modulesloaded);//hook event that all plugins are loaded
	assert(hHookModulesLoaded);
	hHookPreShutdown = HookEvent(ME_SYSTEM_PRESHUTDOWN, preshutdown);
	return 0;
}
//options page on miranda called
INT_PTR CALLBACK DlgProcConnectionNotifyOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
	HWND hwndList;
	switch(msg) {
	case WM_INITDIALOG://initialize dialog, so set properties from db.
		{
			LVCOLUMN lvc={0};
			LVITEM lvI={0};
			TCHAR buff[256];
			struct CONNECTION *tmp=connExceptions;
			bOptionsOpen=TRUE;
			TranslateDialogDefault(hwndDlg);//translate miranda function
#ifdef _WIN64
			mir_sntprintf(buff,SIZEOF(buff),_T("%d.%d.%d.%d/64"), HIBYTE(HIWORD(pluginInfo.version)), LOBYTE(HIWORD(pluginInfo.version)), HIBYTE(LOWORD(pluginInfo.version)), LOBYTE(LOWORD(pluginInfo.version)));
#else
			mir_sntprintf(buff,SIZEOF(buff),_T("%d.%d.%d.%d/32"), HIBYTE(HIWORD(pluginInfo.version)), LOBYTE(HIWORD(pluginInfo.version)), HIBYTE(LOWORD(pluginInfo.version)), LOBYTE(LOWORD(pluginInfo.version)));
#endif
			SetDlgItemText(hwndDlg, IDC_VERSION, buff);
			LoadSettings();
			//connExceptionsTmp=LoadSettingsConnections();
			SetDlgItemInt(hwndDlg, IDC_INTERVAL , settingInterval,FALSE);
			SetDlgItemInt(hwndDlg, IDC_INTERVAL1 , settingInterval1,TRUE);
			CheckDlgButton(hwndDlg, IDC_SETCOLOURS, settingSetColours ? TRUE : FALSE);
			CheckDlgButton(hwndDlg, IDC_RESOLVEIP, settingResolveIp ? TRUE : FALSE);
			CheckDlgButton(hwndDlg, ID_CHK_DEFAULTACTION, settingDefaultAction ? TRUE : FALSE);

			SendDlgItemMessage(hwndDlg, IDC_BGCOLOR, CPM_SETCOLOUR, 0, (LPARAM)settingBgColor);
			SendDlgItemMessage(hwndDlg, IDC_FGCOLOR, CPM_SETCOLOUR, 0, (LPARAM)settingFgColor);
			if (!settingSetColours) {
				HWND hwnd = GetDlgItem(hwndDlg, IDC_BGCOLOR);
				CheckDlgButton(hwndDlg, IDC_SETCOLOURS, FALSE);
				EnableWindow(hwnd, FALSE);
				hwnd = GetDlgItem(hwndDlg, IDC_FGCOLOR);
				EnableWindow(hwnd, FALSE);
			}
			SendDlgItemMessage(hwndDlg, ID_ADD, BM_SETIMAGE, IMAGE_ICON, (LPARAM)LoadImage(hInst,MAKEINTRESOURCE(IDI_ICON6),IMAGE_ICON,16,16,0));
			SendDlgItemMessage(hwndDlg, ID_DELETE, BM_SETIMAGE, IMAGE_ICON, (LPARAM)LoadImage(hInst,MAKEINTRESOURCE(IDI_ICON3),IMAGE_ICON,16,16,0));	
			SendDlgItemMessage(hwndDlg, ID_DOWN, BM_SETIMAGE, IMAGE_ICON, (LPARAM)LoadImage(hInst,MAKEINTRESOURCE(IDI_ICON4),IMAGE_ICON,16,16,0));
			SendDlgItemMessage(hwndDlg, ID_UP, BM_SETIMAGE, IMAGE_ICON, (LPARAM)LoadImage(hInst,MAKEINTRESOURCE(IDI_ICON5),IMAGE_ICON,16,16,0));
			// initialise and fill listbox
			hwndList = GetDlgItem(hwndDlg, IDC_STATUS);
			ListView_DeleteAllItems(hwndList);
			SendMessage(hwndList,LVM_SETEXTENDEDLISTVIEWSTYLE, 0,LVS_EX_FULLROWSELECT | LVS_EX_CHECKBOXES);
			// Initialize the LVCOLUMN structure.
			// The mask specifies that the format, width, text, and
			// subitem members of the structure are valid. 
			lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; 
			lvc.fmt = LVCFMT_LEFT;
			lvc.iSubItem = 0;
			lvc.pszText = TranslateT("Status");	
			lvc.cx = 120;     // width of column in pixels
			ListView_InsertColumn(hwndList, 0, &lvc);
			// Some code to create the list-view control.
			// Initialize LVITEM members that are common to all
			// items. 
			lvI.mask = LVIF_TEXT;
			for(int i = 0; i < STATUS_COUNT; i++) {
				lvI.pszText = (TCHAR*)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, ID_STATUS_ONLINE+i, GSMDF_TCHAR);
				lvI.iItem = i;
				ListView_InsertItem(hwndList, &lvI);
				ListView_SetCheckState(hwndList, i, settingStatus[i]);
			}

			connExceptionsTmp=LoadSettingsConnections();
			hwndList = GetDlgItem(hwndDlg, IDC_LIST_EXCEPTIONS);
			SendMessage(hwndList,LVM_SETEXTENDEDLISTVIEWSTYLE, 0,LVS_EX_FULLROWSELECT);

			lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; 
			lvc.fmt = LVCFMT_LEFT;
			lvc.iSubItem = 0;
			lvc.cx = 120;     // width of column in pixels
			lvc.pszText = TranslateT("Application");
			ListView_InsertColumn(hwndList, 1, &lvc);
			lvc.pszText = TranslateT("Internal socket");	
			ListView_InsertColumn(hwndList, 2, &lvc);
			lvc.pszText = TranslateT("External socket");
			ListView_InsertColumn(hwndList, 3, &lvc);
			lvc.pszText = TranslateT("Action");
			lvc.cx = 50;
			ListView_InsertColumn(hwndList, 4, &lvc);

			//fill exceptions list
			fillExceptionsListView(hwndDlg);
		}
		break;

	case WM_COMMAND://user changed something, so get changes to variables
		PostMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
		switch(LOWORD(wParam)) {
		case IDC_INTERVAL: settingInterval =GetDlgItemInt(hwndDlg, IDC_INTERVAL, NULL, FALSE); break;
		case IDC_INTERVAL1: settingInterval1 =GetDlgItemInt(hwndDlg, IDC_INTERVAL1, NULL, TRUE); break;
		case IDC_RESOLVEIP: settingResolveIp=(BYTE) IsDlgButtonChecked(hwndDlg, IDC_RESOLVEIP); break;
		case ID_CHK_DEFAULTACTION: settingDefaultAction=(BYTE) IsDlgButtonChecked(hwndDlg, ID_CHK_DEFAULTACTION); break;
		case ID_ADD:
			{
				struct CONNECTION *cur=(struct CONNECTION *)mir_alloc(sizeof(struct CONNECTION));
				memset(cur,0,sizeof(struct CONNECTION));
				cur->intExtPort=-1;
				cur->intIntPort=-1;
				cur->Pid=0;
				cur->PName[0]='*';
				cur->strExtIp[0]='*';
				cur->strIntIp[0]='*';

				if (DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_FILTER_DIALOG), hwndDlg, FilterEditProc, (LPARAM)cur)==IDCANCEL) {
					mir_free(cur);
					cur = NULL;
				}
				else {
					cur->next = connExceptionsTmp;
					connExceptionsTmp = cur;
				}

				fillExceptionsListView(hwndDlg);
				ListView_SetItemState(GetDlgItem(hwndDlg,IDC_LIST_EXCEPTIONS),0,LVNI_FOCUSED|LVIS_SELECTED , LVNI_FOCUSED|LVIS_SELECTED );
				SetFocus(GetDlgItem(hwndDlg,IDC_LIST_EXCEPTIONS));
			}
			break;

		case ID_DELETE: 
			{
				int pos,pos1;
				struct CONNECTION *cur = connExceptionsTmp, *pre = NULL;

				pos=(int)ListView_GetNextItem(GetDlgItem(hwndDlg, IDC_LIST_EXCEPTIONS),-1,LVNI_FOCUSED );
				if (pos==-1)break;
				pos1=pos;
				while(pos--)
				{
					pre=cur;
					cur=cur->next;
				}
				if (pre==NULL)
					connExceptionsTmp=connExceptionsTmp->next;
				else
					(pre)->next=cur->next;
				mir_free(cur);
				fillExceptionsListView(hwndDlg);
				ListView_SetItemState(GetDlgItem(hwndDlg,IDC_LIST_EXCEPTIONS),pos1,LVNI_FOCUSED|LVIS_SELECTED , LVNI_FOCUSED|LVIS_SELECTED );
				SetFocus(GetDlgItem(hwndDlg,IDC_LIST_EXCEPTIONS));
				break;
			}
		case ID_UP: 
			{
				int pos,pos1;
				struct CONNECTION *cur=NULL,*pre=NULL,*prepre=NULL;

				cur=connExceptionsTmp;

				pos=(int)ListView_GetNextItem(GetDlgItem(hwndDlg, IDC_LIST_EXCEPTIONS),-1,LVNI_FOCUSED );
				if (pos==-1)break;
				pos1=pos;
				while(pos--)
				{
					prepre=pre;
					pre=cur;
					cur=cur->next;
				}
				if (prepre!=NULL)
				{
					pre->next=cur->next;
					cur->next=pre;
					prepre->next=cur;
				}
				else if (pre!=NULL)
				{
					pre->next=cur->next;
					cur->next=pre;
					connExceptionsTmp=cur;							
				}
				fillExceptionsListView(hwndDlg);
				ListView_SetItemState(GetDlgItem(hwndDlg,IDC_LIST_EXCEPTIONS),pos1-1,LVNI_FOCUSED|LVIS_SELECTED , LVNI_FOCUSED|LVIS_SELECTED );
				SetFocus(GetDlgItem(hwndDlg,IDC_LIST_EXCEPTIONS));
				break;
			}
		case ID_DOWN: 
			{
				int pos,pos1;
				struct CONNECTION *cur=NULL,*pre=NULL;

				cur=connExceptionsTmp;

				pos=(int)ListView_GetNextItem(GetDlgItem(hwndDlg, IDC_LIST_EXCEPTIONS),-1,LVNI_FOCUSED );
				if (pos==-1)break;
				pos1=pos;
				while(pos--)
				{
					pre=cur;
					cur=cur->next;
				}
				if (cur==connExceptionsTmp&&cur->next!=NULL)
				{
					connExceptionsTmp=cur->next;
					cur->next=cur->next->next;
					connExceptionsTmp->next=cur;
				}
				else if (cur->next!=NULL)
				{
					struct CONNECTION *tmp=cur->next->next;
					pre->next=cur->next;
					cur->next->next=cur;
					cur->next=tmp;
				}
				fillExceptionsListView(hwndDlg);
				ListView_SetItemState(GetDlgItem(hwndDlg,IDC_LIST_EXCEPTIONS),pos1+1,LVNI_FOCUSED|LVIS_SELECTED , LVNI_FOCUSED|LVIS_SELECTED );
				SetFocus(GetDlgItem(hwndDlg,IDC_LIST_EXCEPTIONS));
				break;
			}				
		case IDC_SETCOLOURS:
			{
				HWND hwnd = GetDlgItem(hwndDlg, IDC_BGCOLOR);
				settingSetColours=IsDlgButtonChecked(hwndDlg, IDC_SETCOLOURS);
				EnableWindow(hwnd,settingSetColours );
				hwnd = GetDlgItem(hwndDlg, IDC_FGCOLOR);
				EnableWindow(hwnd, settingSetColours);
				break;
			}
		case IDC_BGCOLOR: settingBgColor = (COLORREF)SendDlgItemMessage(hwndDlg, IDC_BGCOLOR, CPM_GETCOLOUR, 0, 0);break;
		case IDC_FGCOLOR: settingFgColor = (COLORREF)SendDlgItemMessage(hwndDlg, IDC_FGCOLOR, CPM_GETCOLOUR, 0, 0);break;

		}
		break;

	case WM_NOTIFY://apply changes so write it to db
		switch(((LPNMHDR)lParam)->idFrom) {
		case 0:
			switch (((LPNMHDR)lParam)->code) {
			case PSN_RESET:
				LoadSettings();
				deleteConnectionsTable(connExceptionsTmp);
				connExceptionsTmp=LoadSettingsConnections();
				return TRUE;

			case PSN_APPLY:
				db_set_dw (NULL, PLUGINNAME, "Interval", settingInterval );
				db_set_dw (NULL, PLUGINNAME, "PopupInterval", settingInterval1 );
				db_set_b(NULL, PLUGINNAME, "PopupSetColours", settingSetColours);
				db_set_dw(NULL, PLUGINNAME, "PopupBgColor", (DWORD)settingBgColor);
				db_set_dw(NULL, PLUGINNAME, "PopupFgColor", (DWORD)settingFgColor);
				db_set_b(NULL, PLUGINNAME, "ResolveIp", settingResolveIp);
				db_set_b(NULL, PLUGINNAME, "FilterDefaultAction", settingDefaultAction);

				for(int i = 0; i < STATUS_COUNT ; i++) {
					char buff[128];
					mir_snprintf(buff,_countof(buff), "Status%d", i);
					settingStatus[i] = (ListView_GetCheckState(GetDlgItem(hwndDlg, IDC_STATUS), i) ? TRUE : FALSE);
					db_set_b(0, PLUGINNAME, buff, settingStatus[i] ? 1 : 0);
				}
				if (WAIT_OBJECT_0 == WaitForSingleObject(hExceptionsMutex, 100)) {
					deleteConnectionsTable(connExceptions);
					saveSettingsConnections(connExceptionsTmp);
					connExceptions = connExceptionsTmp;
					connExceptionsTmp = LoadSettingsConnections();
					ReleaseMutex(hExceptionsMutex);
				}
				return TRUE;
			}
			break;
		}

		if (GetDlgItem(hwndDlg, IDC_LIST_EXCEPTIONS)==((LPNMHDR) lParam)->hwndFrom) {
			switch (((LPNMHDR) lParam)->code) {
			case NM_DBLCLK:
				{
					int pos,pos1;
					struct CONNECTION *cur=NULL;

					cur=connExceptionsTmp;

					pos=(int)ListView_GetNextItem(GetDlgItem(hwndDlg, IDC_LIST_EXCEPTIONS),-1,LVNI_FOCUSED );
					if (pos==-1)break;
					pos1=pos;
					while(pos--)
					{
						cur=cur->next;
					}
					DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_FILTER_DIALOG), hwndDlg, FilterEditProc, (LPARAM)cur);
					fillExceptionsListView(hwndDlg);
					ListView_SetItemState(GetDlgItem(hwndDlg,IDC_LIST_EXCEPTIONS),pos1,LVNI_FOCUSED|LVIS_SELECTED , LVNI_FOCUSED|LVIS_SELECTED );
					SetFocus(GetDlgItem(hwndDlg,IDC_LIST_EXCEPTIONS));
					break;
				}
			}
		}

		if (GetDlgItem(hwndDlg, IDC_STATUS) == ((LPNMHDR) lParam)->hwndFrom) {
			switch (((LPNMHDR) lParam)->code) {
			case LVN_ITEMCHANGED:
				NMLISTVIEW *nmlv = (NMLISTVIEW *)lParam;
				if ((nmlv->uNewState ^ nmlv->uOldState) & LVIS_STATEIMAGEMASK)
					SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 );
				break;
			}
		}
		break;

	case WM_DESTROY:
		bOptionsOpen=FALSE;
		deleteConnectionsTable(connExceptionsTmp);
		connExceptionsTmp=NULL;
		return TRUE;
	}
	return 0;
}