{Statistic} unit proto; {$include compilers.inc} interface {$Resource proto.res} implementation uses windows,messages,commctrl, common,m_api,mirutils,mircontacts,dbsettings,wrapper, global,wat_api; {$include resource.inc} {$include i_proto_rc.inc} const ShareOptText = 'ShareMusic'; const IcoBtnContext:PAnsiChar='WATrack_Context'; const MenuUserInfoPos = 500050000; const wpRequest = 'WAT###0_'; wpAnswer = 'WAT###1_'; wpError = 'WAT###2_'; wpMessage = 'WAT###3_'; wpRequestNew = 'ASKWAT'; const SendRequestText:PAnsiChar = 'WATrack internal info - sorry!'; { 'If you see this message, probably you have no WATrack plugin installed or uses old '+ 'version. See https://miranda-ng.org/p/Watrack for '+ 'more information and download.'; } const hmInRequest = $0001; hmOutRequest = $0002; hmInInfo = $0004; hmOutInfo = $0008; hmInError = $0010; hmOutError = $0020; hmIRequest = $0040; hmISend = $0080; var hSRM, hGCI, hContactMenuItem: THANDLE; ProtoText:pWideChar; HistMask:cardinal; {$include i_proto_opt.inc} {$include i_proto_dlg.inc} procedure AddEvent(hContact:TMCONTACT;atype,flag:integer;data:pointer;size:integer;time:dword=0); var dbeo:TDBEVENTINFO; begin FillChar(dbeo,SizeOf(dbeo),0); with dbeo do begin eventType:=atype; szModule :=PluginShort; if data=nil then begin PAnsiChar(data):=''; size:=1; end; pBlob :=data; cbBlob :=size; flags :=flag; if time<>0 then Timestamp:=time else Timestamp:=GetCurrentTime; end; db_event_add(hContact, @dbeo); end; function ReceiveMessageProcW(wParam:WPARAM; lParam:LPARAM):int_ptr; cdecl; const bufsize = 4096*SizeOf(WideChar); var ccs:PCCSDATA; ccdata:TCCSDATA; s:pWideChar; buf:PWideChar; data:PByte; dataSize:int; encodedStr:PAnsiChar; pos_template:pWideChar; curpos:pWideChar; encbuf:pWideChar; i:integer; textpos:PWideChar; pc:PAnsiChar; isNewRequest:bool; si:pSongInfo; begin ccs:=PCCSDATA(lParam); result:=0; mGetMem(buf,bufsize); isNewRequest:=StrCmp(PPROTORECVEVENT(ccs^.lParam)^.szMessage.a, wpRequestNew,Length(wpRequestNew))=0; if isNewRequest or (StrCmp(PPROTORECVEVENT(ccs^.lParam)^.szMessage.a, wpRequest,Length(wpRequest))=0) then begin StrCopy(PAnsiChar(buf),Proto_GetProtoName(ccs^.hContact)); i:=DBReadWord(ccs^.hContact,PAnsiChar(buf),'ApparentMode'); if (i=ID_STATUS_OFFLINE) or ((i=0) and (Proto_GetStatus(PAnsiChar(buf))=ID_STATUS_INVISIBLE)) then begin result:=Proto_ChainRecv(wParam,ccs); end else if DBReadByte(ccs^.hContact,strCList,ShareOptText,0)<>0 then // or (NotListedAllow and (DBReadByte(ccs^.hContact,strCList,'NotOnList',0)) begin if (HistMask and hmInRequest)<>0 then AddEvent(ccs^.hContact,EVENTTYPE_WAT_REQUEST,DBEF_READ,nil,0, PPROTORECVEVENT(ccs^.lParam)^.Timestamp); if GetContactStatus(ccs^.hContact)<>ID_STATUS_OFFLINE then begin //!! Request Answer curpos:=nil; if DisablePlugin<>dsPermanent then begin if CallService(MS_WAT_GETMUSICINFO,0,0)=WAT_RES_NOTFOUND then begin s:=#0#0#0'No player found at this time'; textpos:=s+3; end else begin if not isNewRequest then begin FillChar(buf^,bufsize,0); si:=pSongInfo(CallService(MS_WAT_RETURNGLOBAL,0,0)); StrCopyW(buf ,si^.artist); curpos:=StrEndW(buf)+1; StrCopyW(curpos,si^.title); curpos:=StrEndW(curpos)+1; StrCopyW(curpos,si^.album); curpos:=StrEndW(curpos)+1; end else curpos:=buf; //!! check to DisableTemporary s:=PWideChar(CallService(MS_WAT_REPLACETEXT,0,tlparam(ProtoText))); textpos:=StrCopyW(curpos,s); mFreeMem(s); curpos:=StrEndW(curpos)+1; end; end else begin s:=#0#0#0'Sorry, but i don''t use WATrack right now!'; textpos:=s+3; end; // encode if not isNewRequest then begin if curpos<>nil then begin data:=PByte(buf); dataSize:=PAnsiChar(curpos)-PAnsiChar(buf); end else begin data:=PByte(s); dataSize:=(StrLenW(textpos)+3+1)*SizeOf(PWideChar); end; encodedStr:=mir_base64_encode(data,dataSize); mGetMem(encbuf,Length(encodedStr)+1+Length(wpAnswer)); StrCopy(PAnsiChar(encbuf),wpAnswer); StrCopy(PAnsiChar(encbuf)+Length(wpAnswer),encodedStr); mFreeMem(encodedStr); if (HistMask and hmOutInfo)<>0 then AddEvent(ccs^.hContact,EVENTTYPE_WAT_ANSWER,DBEF_SENT,data,dataSize); ccdata.hContact := ccs^.hContact; ccdata.szProtoService := PSS_MESSAGE; ccdata.wParam := 0; ccdata.lParam := tlparam(encbuf); Proto_ChainSend(0, @ccdata); mFreeMem(encbuf); end else begin WideToUTF8(textpos,encodedStr); if (HistMask and hmOutInfo)<>0 then AddEvent(ccs^.hContact,EVENTTYPE_WAT_MESSAGE,DBEF_SENT or DBEF_UTF,encodedStr,StrLen(encodedStr)); ccdata.hContact := ccs^.hContact; ccdata.szProtoService := PSS_MESSAGE; ccdata.wParam := 0; ccdata.lParam := tlparam(encodedStr); Proto_ChainSend(0, @ccdata); mFreeMem(encodedStr); end; end; end else begin if (HistMask and hmIRequest)<>0 then AddEvent(ccs^.hContact,EVENTTYPE_WAT_REQUEST,DBEF_READ,nil,0, PPROTORECVEVENT(ccs^.lParam)^.Timestamp); if (HistMask and hmISend)<>0 then begin //!! Request Error Answer if isNewRequest then pc:=PAnsiChar(buf) else begin StrCopy(PAnsiChar(buf),wpError); pc:=PAnsiChar(buf)+Length(wpError); end; StrCopy(pc,'Sorry, but you have no permission to obtain this info!'); ccdata.hContact := ccs^.hContact; ccdata.szProtoService := PSS_MESSAGE; ccdata.wParam := 0; ccdata.lParam := tlparam(buf); Proto_ChainSend(0, @ccdata); if (HistMask and hmOutError)<>0 then begin AddEvent(ccs^.hContact,EVENTTYPE_WAT_ERROR,DBEF_SENT,nil,0, PPROTORECVEVENT(ccs^.lParam)^.Timestamp); end; end; end; end else if StrCmp(PPROTORECVEVENT(ccs^.lParam)^.szMessage.a,wpAnswer,Length(wpAnswer))=0 then begin // decode data:=mir_base64_decode(PPROTORECVEVENT(ccs^.lParam)^.szMessage.a+Length(wpAnswer),dataSize); curpos:=pWideChar(data); // pos_artist:=curpos; while curpos^<>#0 do inc(curpos); inc(curpos); // pos_title :=curpos; while curpos^<>#0 do inc(curpos); inc(curpos); // pos_album :=curpos; while curpos^<>#0 do inc(curpos); inc(curpos); pos_template:=curpos; if (HistMask and hmInInfo)<>0 then AddEvent(ccs^.hContact,EVENTTYPE_WAT_ANSWER,DBEF_READ, data,dataSize, PPROTORECVEVENT(ccs^.lParam)^.Timestamp); // Action StrCopyW(buf,TranslateW('Music Info from ')); StrCatW(buf,Clist_GetContactDisplayName(ccs^.hContact,0)); MessageBoxW(0,TranslateW(pos_template),buf,MB_ICONINFORMATION); mFreeMem(data); end else if StrCmp(PPROTORECVEVENT(ccs^.lParam)^.szMessage.a,wpError,Length(wpError))=0 then begin if (HistMask and hmInError)<>0 then AddEvent(ccs^.hContact,EVENTTYPE_WAT_ERROR,DBEF_READ,nil,0, PPROTORECVEVENT(ccs^.lParam)^.Timestamp); MessageBoxA(0,Translate(PPROTORECVEVENT(ccs^.lParam)^.szMessage.a+Length(wpError)), Translate('You Get Error'),MB_ICONERROR); end else result:=Proto_ChainRecv(wParam,ccs); mFreeMem(buf); end; function SendRequest(hContact:WPARAM;lParam:LPARAM):int_ptr; cdecl; var buf:array [0..2047] of AnsiChar; ccdata:TCCSDATA; begin result:=0; StrCopy(buf,wpRequest); StrCopy(buf+Length(wpRequest),SendRequestText); ccdata.hContact := hContact; ccdata.szProtoService := PSS_MESSAGE; ccdata.wParam := 0; ccdata.lParam := tlparam(@buf); Proto_ChainSend(0, @ccdata); if (HistMask and hmOutRequest)<>0 then AddEvent(hContact,EVENTTYPE_WAT_REQUEST,DBEF_SENT,nil,0); end; procedure RegisterContacts; var hContact:TMCONTACT; begin hContact:=db_find_first(); while hContact<>0 do begin if not IsChat(hContact) then Proto_AddToContact(hContact,PluginShort); hContact:=db_find_next(hContact); end; end; function HookAddUser(hContact:WPARAM;lParam:LPARAM):int; cdecl; begin result:=0; if not IsChat(hContact) then Proto_AddToContact(hContact,PluginShort); end; function OnContactMenu(hContact:WPARAM;lParam:LPARAM):int;cdecl; begin if IsMirandaUser(hContact)<=0 then Menu_ShowItem(hContactMenuItem, 0) else Menu_ShowItem(hContactMenuItem, 1); result:=0; end; procedure SetProtocol; begin Proto_RegisterModule(PROTOTYPE_TRANSLATION,PluginShort); hSRM:=CreateProtoServiceFunction(PluginShort,PSR_MESSAGE ,@ReceiveMessageProcW); end; procedure RegisterIcons; var sid:TSKINICONDESC; begin FillChar(sid,SizeOf(TSKINICONDESC),0); sid.cx:=16; sid.cy:=16; sid.szSection.a:=PluginShort; sid.hDefaultIcon :=LoadImage(hInstance,MAKEINTRESOURCE(BTN_CONTEXT),IMAGE_ICON,16,16,0); sid.pszName :=IcoBtnContext; sid.szDescription.a:='Context Menu'; Skin_AddIcon(@sid); DestroyIcon(sid.hDefaultIcon); end; // ------------ base interface functions ------------- function InitProc(aGetStatus:boolean=false):integer; var mi:TMO_MenuItem; begin if aGetStatus then begin if GetModStatus=0 then begin result:=0; exit; end; end else SetModStatus(1); result:=1; ReadOptions; RegisterIcons; FillChar(mi, sizeof(mi), 0); mi.root := Menu_CreateRoot(MO_CONTACT, 'WATrack', 0, 0, 0); Menu_ConfigureItem(mi.root, MCI_OPT_UID, 'CAEA4B95-A873-429F-A083-BB2DF51E2E45'); SET_UID(@mi, '47D372B2-AA27-42B3-A3CB-85D3CE5F6A95'); mi.flags := CMIF_NOTOFFLINE or CMIF_NOTOFFLIST; mi.hIcon := IcoLib_GetIcon(IcoBtnContext,0); mi.szName.a := 'Get user''s Music Info'; mi.pszService := MS_WAT_GETCONTACTINFO; hContactMenuItem := Menu_AddContactMenuItem(@mi); SetProtocol; RegisterContacts; hGCI:=CreateServiceFunction(MS_WAT_GETCONTACTINFO,@SendRequest); HookEvent(ME_CLIST_PREBUILDCONTACTMENU,@OnContactMenu); HookEvent(ME_DB_CONTACT_ADDED ,@HookAddUser); end; procedure DeInitProc(aSetDisable:boolean); begin if aSetDisable then SetModStatus(0); DestroyServiceFunction(hSRM); DestroyServiceFunction(hGCI); mFreeMem(ProtoText); end; function AddOptionsPage(var tmpl:pAnsiChar;var proc:pointer;var name:PAnsiChar):integer; begin tmpl:=PAnsiChar(IDD_OPT_MISC); proc:=@DlgProcOptions; name:='Misc'; result:=0; end; var vproto:twModule; procedure Init; begin vproto.Next :=ModuleLink; vproto.Init :=@InitProc; vproto.DeInit :=@DeInitProc; vproto.AddOption :=@AddOptionsPage; vproto.Check :=nil; vproto.ModuleName:='Protocol'; ModuleLink :=@vproto; end; begin Init; end.