From cb4a46e7fbe62d788e66ed6121c717a2d22a4d7c Mon Sep 17 00:00:00 2001 From: watcherhd Date: Thu, 21 Apr 2011 14:14:52 +0000 Subject: svn.miranda.im is moving to a new home! git-svn-id: http://miranda-plugins.googlecode.com/svn/trunk@7 e753b5eb-9565-29b2-b5c5-2cc6f99dfbcb --- importtxt/BICQ5IP.inc | 112 +++++++ importtxt/BICQ6IP.inc | 91 ++++++ importtxt/BRMSIP.inc | 77 +++++ importtxt/BbayanIP.inc | 77 +++++ importtxt/BmContactIP.inc | 58 ++++ importtxt/BqhfIP.inc | 131 ++++++++ importtxt/FileDlgs.pas | 131 ++++++++ importtxt/General.pas | 562 +++++++++++++++++++++++++++++++ importtxt/ImpDlgRes.inc | 12 + importtxt/ImpTxtDlg.rc | 18 + importtxt/ImpTxtDlg.res | Bin 0 -> 3264 bytes importtxt/ImpTxtWiz.rc | 64 ++++ importtxt/ImpTxtWiz.res | Bin 0 -> 2840 bytes importtxt/ImpTxt_Ver.rc | 28 ++ importtxt/ImpTxt_Ver.res | Bin 0 -> 1056 bytes importtxt/ImpWizRes.inc | 21 ++ importtxt/ImportT.pas | 82 +++++ importtxt/ImportTU.pas | 260 +++++++++++++++ importtxt/ImportThrd.pas | 599 ++++++++++++++++++++++++++++++++++ importtxt/ImportTxtWiz.pas | 369 +++++++++++++++++++++ importtxt/PerlRegEx.pas | 447 +++++++++++++++++++++++++ importtxt/doc/changelog_ru.txt | 77 +++++ importtxt/doc/examples_ru.txt | 169 ++++++++++ importtxt/doc/importtxt_translate.txt | 105 ++++++ importtxt/doc/pattern_cfg_ru.txt | 77 +++++ importtxt/doc/readme_ru.txt | 78 +++++ importtxt/ico/def_ico.ico | Bin 0 -> 2550 bytes importtxt/importtxt.dpr | 202 ++++++++++++ importtxt/importtxt/ICQ5_p.ini | 9 + importtxt/importtxt/ICQ6_p.ini | 5 + importtxt/importtxt/MAgent_p.ini | 23 ++ importtxt/importtxt/QHF_p.ini | 5 + importtxt/importtxt/SEmidprms_p.ini | 5 + importtxt/importtxt/bayanICQ_p.ini | 9 + importtxt/importtxt/dichat_p.ini | 24 ++ importtxt/importtxt/historypp_p.ini | 1 + importtxt/importtxt/jimm_p.ini | 24 ++ importtxt/importtxt/jimmws2_p.ini | 22 ++ importtxt/importtxt/jimmws_p.ini | 23 ++ importtxt/importtxt/mContact_p.ini | 9 + importtxt/importtxt/msgexport_p.ini | 23 ++ importtxt/importtxt/nokmidprms_p.ini | 9 + importtxt/importtxt/pigeon_p.ini | 23 ++ importtxt/importtxt/qip_p.ini | 23 ++ importtxt/importtxt/smaper_p.ini | 23 ++ importtxt/importtxt/smapern_p.ini | 23 ++ importtxt/importtxtdlg.pas | 233 +++++++++++++ importtxt/make.bat | 10 + 48 files changed, 4373 insertions(+) create mode 100644 importtxt/BICQ5IP.inc create mode 100644 importtxt/BICQ6IP.inc create mode 100644 importtxt/BRMSIP.inc create mode 100644 importtxt/BbayanIP.inc create mode 100644 importtxt/BmContactIP.inc create mode 100644 importtxt/BqhfIP.inc create mode 100644 importtxt/FileDlgs.pas create mode 100644 importtxt/General.pas create mode 100644 importtxt/ImpDlgRes.inc create mode 100644 importtxt/ImpTxtDlg.rc create mode 100644 importtxt/ImpTxtDlg.res create mode 100644 importtxt/ImpTxtWiz.rc create mode 100644 importtxt/ImpTxtWiz.res create mode 100644 importtxt/ImpTxt_Ver.rc create mode 100644 importtxt/ImpTxt_Ver.res create mode 100644 importtxt/ImpWizRes.inc create mode 100644 importtxt/ImportT.pas create mode 100644 importtxt/ImportTU.pas create mode 100644 importtxt/ImportThrd.pas create mode 100644 importtxt/ImportTxtWiz.pas create mode 100644 importtxt/PerlRegEx.pas create mode 100644 importtxt/doc/changelog_ru.txt create mode 100644 importtxt/doc/examples_ru.txt create mode 100644 importtxt/doc/importtxt_translate.txt create mode 100644 importtxt/doc/pattern_cfg_ru.txt create mode 100644 importtxt/doc/readme_ru.txt create mode 100644 importtxt/ico/def_ico.ico create mode 100644 importtxt/importtxt.dpr create mode 100644 importtxt/importtxt/ICQ5_p.ini create mode 100644 importtxt/importtxt/ICQ6_p.ini create mode 100644 importtxt/importtxt/MAgent_p.ini create mode 100644 importtxt/importtxt/QHF_p.ini create mode 100644 importtxt/importtxt/SEmidprms_p.ini create mode 100644 importtxt/importtxt/bayanICQ_p.ini create mode 100644 importtxt/importtxt/dichat_p.ini create mode 100644 importtxt/importtxt/historypp_p.ini create mode 100644 importtxt/importtxt/jimm_p.ini create mode 100644 importtxt/importtxt/jimmws2_p.ini create mode 100644 importtxt/importtxt/jimmws_p.ini create mode 100644 importtxt/importtxt/mContact_p.ini create mode 100644 importtxt/importtxt/msgexport_p.ini create mode 100644 importtxt/importtxt/nokmidprms_p.ini create mode 100644 importtxt/importtxt/pigeon_p.ini create mode 100644 importtxt/importtxt/qip_p.ini create mode 100644 importtxt/importtxt/smaper_p.ini create mode 100644 importtxt/importtxt/smapern_p.ini create mode 100644 importtxt/importtxtdlg.pas create mode 100644 importtxt/make.bat (limited to 'importtxt') diff --git a/importtxt/BICQ5IP.inc b/importtxt/BICQ5IP.inc new file mode 100644 index 0000000..b3b7d30 --- /dev/null +++ b/importtxt/BICQ5IP.inc @@ -0,0 +1,112 @@ +{$ifdef BIN_IMPORT_} +var + XI:XML_API; + rhxml:HXML; + curxml:HXML; + chldxml:HXML; + ptxt:PWideChar; + txtlen:int; + ic,tm:integer; + res:LongBool; + +{$else} +begin + If pluginLink^.ServiceExists(MS_SYSTEM_GET_XI)>0 then + begin + XI.cbSize:=SizeOf(XML_API); + res:=longbool(pluginLink^.CallService(MS_SYSTEM_GET_XI,0,Int(@XI))); + if not res then + begin + XI.cbSize:=SizeOf(XML_API)-4; + res:=longbool(pluginLink^.CallService(MS_SYSTEM_GET_XI,0,Int(@XI))); + if not res then + begin + s:=TranslateWideString('Error at initialization XML parser'); + DoMessage(ITXT_THREAD_ERROR,integer(PWideChar(s)),0); + exit; + end; + end; + end + else + begin + s:=TranslateWideString('Your version of Miranda don''t support XML parsing'); + DoMessage(ITXT_THREAD_ERROR,integer(PWideChar(s)),0); + exit; + end; + if (DContact.hContact=0) or (DContact.hContact=INVALID_HANDLE_VALUE) then + if (fContact.hContact<>0) and (fContact.hContact<>INVALID_HANDLE_VALUE) then + DContact:=fContact; + if (DContact.hContact<>0) and (DContact.hContact<>INVALID_HANDLE_VALUE) then + begin + proto:=GetContactProto(DContact.hContact); + DoMessage(ITXT_THREAD_DEST_CONTACT,DContact.hContact,0); + DoMessage(ITXT_THREAD_START,0,0); + GetMem(ptxt,SizeOf(WideChar)*FileLen+2); + try + ptxt:=UTF8toWide(pFileText,ptxt,SizeOf(WideChar)*FileLen+2); + ptxt[FileLen+1]:=#0000; + rhxml:=XI.parseString(ptxt,@txtlen,'root'); + finally + freemem(ptxt); + end; + if (rhxml=0) then exit; + DoMessage(ITXT_THREAD_MAXPROGRESS,0,xi.getChildCount(rhxml)); + chldxml:=xi.getFirstChild(rhxml); + if xi.getName(chldxml)='version' then + begin + ic:=0; + curxml:=xi.getNextChild(rhxml,'event',@ic); + while (curxml<>0) do + begin + fillchar(dbei,sizeof(dbei),0); + dbei.cbSize:=sizeof(dbei); + dbei.szModule:=PChar(proto); + if TryStrToInt(xi.getText(xi.getChildByPath(curxml,'time',false)),tm) then dbei.timestamp:=tm; + if xi.getText(xi.getChildByPath(curxml,'incoming',false))='Yes' then dbei.flags:=DBEF_READ + else dbei.flags:=DBEF_SENT or DBEF_READ; + if isMirandaUnicode then dbei.flags:=dbei.flags or DBEF_UTF; + + if xi.getText(xi.getChildByPath(curxml,'type',false))^='2' then + begin + s:=xi.getText(xi.getChildByPath(curxml,'text',false))+': '+ + xi.getText(xi.getChildByPath(curxml,'data',false)); + dbei.eventType:= EVENTTYPE_URL; + end + else + begin + s:=xi.getText(xi.getChildByPath(curxml,'text',false)); + dbei.eventType:= EVENTTYPE_MESSAGE; + end; + try + if IsMirandaUnicode then tempstr:=WidetoUTF8(PWideChar(s),tempstr) + else tempstr:=WideToANSI(PWideChar(s),tempstr,cp); + dbei.cbBlob:=lstrlen(tempstr)+1; + dbei.pBlob:=PByte(tempstr); + if not IsDuplicateEvent(DContact.hContact,dbei) then + if pluginLink^.CallService(MS_DB_EVENT_ADD, wParam(DContact.hContact), lParam(@dbei))<>0 then Inc(AddedMessages) + else begin + s:= 'Error adding message to DB'; + DoMessage(ITXT_THREAD_ERROR,integer(PWideChar(s)),0); break; end + + else Inc(Duplicates); + + finally + FreeMem(tempstr); + curxml:=xi.getNextChild(rhxml,'event',@ic); + DoMessage(ITXT_THREAD_PROGRESS,ic,0); + end; + end; + end + else + begin + s:=WideFormat(TranslateWideString('Its not %s file'),['ICQ5']); + DoMessage(ITXT_THREAD_ERROR,integer(PWideChar(s)),0); + end; + end + else + begin + s:=TranslateWideString('Can''t determine destination contact'); + DoMessage(ITXT_THREAD_ERROR,integer(PWideChar(s)),0); + end; +end; +{$endif} \ No newline at end of file diff --git a/importtxt/BICQ6IP.inc b/importtxt/BICQ6IP.inc new file mode 100644 index 0000000..af8c197 --- /dev/null +++ b/importtxt/BICQ6IP.inc @@ -0,0 +1,91 @@ +{$ifdef BIN_IMPORT_} +var DS: PDataSource; + SS: PSession; + QR1: PQuery; + +var + OneContact:boolean; + flags:integer; + timestamp:LongWord; + Msg:string; + +function FindUIDinDB(too:string):string; +var QR2:PQuery; +begin + QR2:= NewQuery( SS ); + QR2.Text := 'select to, UID from ChatHistory WHERE to='+too; + QR2.Open; + QR2.First; + result:=QR2.FieldByNameAsStr['UID']; + QR2.Free; +end; + +{$else} +begin + DoUnMapFile; + OneContact:=(DContact.hContact<>0) and (DContact.hContact<>INVALID_HANDLE_VALUE); + try + DS := NewDataSource( 'Provider=Microsoft.Jet.OLEDB.4.0;User ID=Admin;' + + 'Data Source='+FileName+ + ';Mode=Share Deny None;' + + 'Extended Properties="";' + + 'Locale Identifier=1033;' + + 'Persist Security Info=False;'); + SS := NewSession( DS ); + QR1 := NewQuery( SS ); + QR1.Text:= 'SELECT Messages.from, date, to, type, subType, subject FROM Messages'; + QR1.Open; + if (QR1.ColCount=7) then + begin + DoMessage(ITXT_THREAD_START,0,0); + QR1.First; + DoMessage(ITXT_THREAD_MAXPROGRESS,0,QR1.RowCount); + While not QR1.EOF do + begin + try + if (QR1.SFieldByName[ 'type' ]='Text') and + (QR1.SFieldByName[ 'subType' ]='IM') then + begin + UIDStr:=FindUIDinDB(QR1.FieldByNameAsStr[ 'to' ]); + if not OneContact then + begin + DContact.ContactUID:=UIDStr; + TryDetermContact(DContact); + end; + if (DContact.hContact<>0) and (DContact.hContact<>INVALID_HANDLE_VALUE) then + begin + if QR1.SField[ 1 ]='' then flags:=DBEF_SENT or DBEF_READ + else flags:=DBEF_READ; + if IsMirandaUnicode then flags:=flags or DBEF_UTF; + timestamp:=DateTimeToTimeStamp(QR1.DFieldByName['date']-693594); + Msg:=QR1.SFieldByName['subject']; + if IsMirandaUnicode then + begin + tempstr:=ANSIToUTF8(PAnsiChar(Msg),tempstr,cp); + Msg:=tempstr; + FreeMem(tempstr); + end; + AddMsgToDB(DContact.hContact,flags,timestamp,Msg,AddedMessages,Duplicates); + end; + end; + except + ShowException(ExceptObject,ExceptAddr) + end; + QR1.Next; + DoMessage(ITXT_THREAD_PROGRESS,QR1.CurIndex,0); + end; //for + end + else + begin + s:=WideFormat(TranslateWideString('Its not %s file'),['ICQ6 mdb']); + DoMessage(ITXT_THREAD_ERROR,integer(PWideChar(s)),0); + end; + finally + DS.Free; + DS := nil; + SS := nil; + QR1 := nil; + end; +end; +{$endif} + diff --git a/importtxt/BRMSIP.inc b/importtxt/BRMSIP.inc new file mode 100644 index 0000000..552a98a --- /dev/null +++ b/importtxt/BRMSIP.inc @@ -0,0 +1,77 @@ +{$ifdef BIN_IMPORT_} +var rsz:integer; + +{$else} +begin + pt:=integer(pFileText); + i:=0; + if FileLen>=$30 then + if (StrLComp(PChar(pt),'midp-rms',8)=0) then + begin + if FileLen>=$48 then + if (RLInteger(pt+$40)=$48) then + begin + fsz:=RLInteger(pt+$44); + i:=$48; + end; + if (RLInteger(pt+$28)=$30) then + begin + fsz:=RLInteger(pt+$2C); + i:=$30; + end; + + if (DContact.hContact=0) or (DContact.hContact=INVALID_HANDLE_VALUE) then + if (fContact.hContact<>0) and (fContact.hContact<>INVALID_HANDLE_VALUE) then + DContact:=fContact; + if (DContact.hContact<>0) and (DContact.hContact<>INVALID_HANDLE_VALUE) then + begin + proto:=GetContactProto(DContact.hContact); + DoMessage(ITXT_THREAD_DEST_CONTACT,DContact.hContact,0); + DoMessage(ITXT_THREAD_START,0,0); + DoMessage(ITXT_THREAD_MAXPROGRESS,0,fsz); + while i0 then Inc(AddedMessages) + else begin + s:= 'Error adding message to DB'; + DoMessage(ITXT_THREAD_ERROR,integer(PWideChar(s)),0); break; end + + else Inc(Duplicates); + finally + inc(i,rsz); + end; + DoMessage(ITXT_THREAD_PROGRESS,i,0); + end; + end + else + begin + s:=TranslateWideString('Can''t determine destination contact'); + DoMessage(ITXT_THREAD_ERROR,integer(PWideChar(s)),0); + end; + end + else + begin + s:=WideFormat(TranslateWideString('Its not %s file'),['midp-rms']); + DoMessage(ITXT_THREAD_ERROR,integer(PWideChar(s)),0); + end + else //file len + +end; +{$endif} diff --git a/importtxt/BbayanIP.inc b/importtxt/BbayanIP.inc new file mode 100644 index 0000000..b37892f --- /dev/null +++ b/importtxt/BbayanIP.inc @@ -0,0 +1,77 @@ +{$ifdef BIN_IMPORT_} +var j:integer; +{$else} +begin + pt:=integer(pFileText); + if FileLen>=10 then + if true {(PWORD(pt)^=$4248) and (PDWORD(pt+2)^=$FFFFFFFF)} then + begin + //смотрим есть ли у нас контакт назначения + if (DContact.hContact=0) or (DContact.hContact=INVALID_HANDLE_VALUE) then + if (fContact.hContact<>0) and (fContact.hContact<>INVALID_HANDLE_VALUE) then + DContact:=fContact; + if (DContact.hContact<>0) and (DContact.hContact<>INVALID_HANDLE_VALUE) then + begin + proto:=GetContactProto(DContact.hContact); + DoMessage(ITXT_THREAD_DEST_CONTACT,DContact.hContact,0); + DoMessage(ITXT_THREAD_START,0,0); + fsz:=FileLen-2; //размер данных в файле + DoMessage(ITXT_THREAD_MAXPROGRESS,0,fsz); + inc(pt,2); + i:=0; + while i0 then Inc(AddedMessages) + else begin + s:= 'Error adding message to DB'; + DoMessage(ITXT_THREAD_ERROR,integer(PWideChar(s)),0); break; end + + else Inc(Duplicates); + inc(i,dbei.cbBlob+$0C); + FreeMem(dbei.pBlob); + DoMessage(ITXT_THREAD_PROGRESS,i,0); + end; + end + else + begin + s:=TranslateWideString('Can''t determine destination contact'); + DoMessage(ITXT_THREAD_ERROR,integer(PWideChar(s)),0); + end; + end + else + begin + s:=WideFormat(TranslateWideString('Its not %s file'),['bayanICQ']); + DoMessage(ITXT_THREAD_ERROR,integer(PWideChar(s)),0); + end + else //file len +end; +{$endif} diff --git a/importtxt/BmContactIP.inc b/importtxt/BmContactIP.inc new file mode 100644 index 0000000..e4fe591 --- /dev/null +++ b/importtxt/BmContactIP.inc @@ -0,0 +1,58 @@ +{$ifdef BIN_IMPORT_} + +{$else} +begin + pt:=integer(pFileText); + if FileLen>=10 then + if (PWORD(pt)^=$4248) and (PDWORD(pt+2)^=$FFFFFFFF) then + begin + //смотрим есть ли у нас контакт назначения + if (DContact.hContact=0) or (DContact.hContact=INVALID_HANDLE_VALUE) then + if (fContact.hContact<>0) and (fContact.hContact<>INVALID_HANDLE_VALUE) then + DContact:=fContact; + if (DContact.hContact<>0) and (DContact.hContact<>INVALID_HANDLE_VALUE) then + begin + proto:=GetContactProto(DContact.hContact); + DoMessage(ITXT_THREAD_DEST_CONTACT,DContact.hContact,0); + DoMessage(ITXT_THREAD_START,0,0); + fsz:=PDWORD(pt+6)^; //размер данных в файле + DoMessage(ITXT_THREAD_MAXPROGRESS,0,fsz); + inc(pt,10); + i:=0; + while i0 then Inc(AddedMessages) + else begin + s:= 'Error adding message to DB'; + DoMessage(ITXT_THREAD_ERROR,integer(PWideChar(s)),0); break; end + + else Inc(Duplicates); + inc(i,dbei.cbSize+dbei.cbBlob); + DoMessage(ITXT_THREAD_PROGRESS,i,0); + end; + end + else + begin + s:=TranslateWideString('Can''t determine destination contact'); + DoMessage(ITXT_THREAD_ERROR,integer(PWideChar(s)),0); + end; + end + else + begin + s:=WideFormat(TranslateWideString('Its not %s file'),['mContact']); + DoMessage(ITXT_THREAD_ERROR,integer(PWideChar(s)),0); + end + else //file len +end; +{$endif} diff --git a/importtxt/BqhfIP.inc b/importtxt/BqhfIP.inc new file mode 100644 index 0000000..236a37d --- /dev/null +++ b/importtxt/BqhfIP.inc @@ -0,0 +1,131 @@ +{$ifdef BIN_IMPORT_} +var + qhfver:byte; + szMsgHd:word; + UIDstr:UTF8String; + UIDLen,NickLen:word; + NickStr:UTF8String; + +function DecodeQHFMsg(ver:byte; adr:integer; cSize:word):string; + +function get1(c: char): byte; +begin + if ShortInt(c)>=0 then Result:=Byte(c) + else Result := Byte(c)+256; +end; + +function get2(b:byte): char; +begin + if b<128 then result:=Char(b) + else result:=Char(b-256); +end; + +var i:integer; +begin + SetLength(Result,cSize); + for i:=1 to cSize do + begin + Result[i]:=PChar(adr+i-1)^; + if ver<>$01 then + begin + inc(Result[i],i); + Result[i]:=get2(255-get1(Result[i])); + end + end; +end; + +{$else} +begin + pt:=integer(pFileText); + if FileLen>=$2E then + if (PChar(pt)^='Q') and (PChar(pt+1)^='H') and (PChar(pt+2)^='F') then + begin + qhfver:=PByte(pt+3)^; + if qhfver>=$03 then szMsgHd:=$23 + else szMsgHd:=$21; + fsz:=RLInteger(pt+$04); + UIDLen:=RLWord(pt+$2C); + SetLength(UIDstr,UIDLen); + if qhfver<=2 then lstrcpynA(PChar(UIDstr),PChar(pt+$2E),UIDLen) + else lstrcpynA(PChar(UIDstr),PChar(pt+$2E),UIDLen+1); + NickLen:=RLWord(pt+$2E+UIDLen); + SetLength(NickStr,NickLen); + if qhfver<=2 then lstrcpynA(PChar(NickStr),PChar(pt+$2E+UIDLen+2),UIDLen) + else lstrcpynA(PChar(NickStr),PChar(pt+$2E+UIDLen+2),UIDLen+1); + inc(pt,$2E+UIDLen+2+NickLen); + if fsz<>FileLen-($2E+UIDLen+2+NickLen) then fsz:= FileLen-($2E+UIDLen+2+NickLen); + if (DContact.hContact=0) or (DContact.hContact=INVALID_HANDLE_VALUE) then + begin + if IsMirandaUnicode then DContact.ContactUID:=UIDstr + else + begin + tempstr:=UTF8ToANSI(PChar(UIDstr),tempstr,cp); + DContact.ContactUID:=tempstr; + FreeMem(tempstr); + end; + if IsMirandaUnicode then DContact.ContactNick:=NickStr + else + begin + tempstr:=UTF8ToANSI(PChar(NickStr),tempstr,cp); + DContact.ContactNick:=tempstr; + FreeMem(tempstr); + end; + TryDetermContact(DContact); + end; + if (DContact.hContact=0) or (DContact.hContact=INVALID_HANDLE_VALUE) then + if (fContact.hContact<>0) and (fContact.hContact<>INVALID_HANDLE_VALUE) then + DContact:=fContact; + if (DContact.hContact<>0) and (DContact.hContact<>INVALID_HANDLE_VALUE) then + begin + proto:=GetContactProto(DContact.hContact); + DoMessage(ITXT_THREAD_DEST_CONTACT,DContact.hContact,0); + DoMessage(ITXT_THREAD_START,0,0); + DoMessage(ITXT_THREAD_MAXPROGRESS,0,fsz); + i:=0; + while i0 then Inc(AddedMessages) + else begin + s:= 'Error adding message to DB'; + DoMessage(ITXT_THREAD_ERROR,integer(PWideChar(s)),0); break; end + + else Inc(Duplicates); + + finally + inc(i,szMsgHd+dbei.cbBlob-1); + FreeMem(dbei.pBlob); + end; + DoMessage(ITXT_THREAD_PROGRESS,i,0); + end; + end + else + begin + s:=TranslateWideString('Can''t determine destination contact'); + DoMessage(ITXT_THREAD_ERROR,integer(PWideChar(s)),0); + end; + end + else + begin + s:=WideFormat(TranslateWideString('Its not %s file'),['QHF']); + DoMessage(ITXT_THREAD_ERROR,integer(PWideChar(s)),0); + end + else //file len +end; +{$endif} \ No newline at end of file diff --git a/importtxt/FileDlgs.pas b/importtxt/FileDlgs.pas new file mode 100644 index 0000000..2257a7a --- /dev/null +++ b/importtxt/FileDlgs.pas @@ -0,0 +1,131 @@ +unit FileDlgs; + +interface + +uses windows,m_api; + +function OpenDialogExecute(hDlg:hWnd; flg:cardinal; var nFO:integer; const DefExt:string):WideString; //Диалог открытия файла +function FolderDialogExecute(hdlg:HWND; var nFO:integer; const DefExt:string):WideString; //Диалог выбора папки + +implementation + +uses shlobj, activex, SysUtils, CommDlg; + +function OpenDialogExecute(hDlg:hWnd; flg:cardinal; var nFO:integer; const DefExt:string):WideString; //Диалог открытия файла +var OpenFilename:TOpenFilenameW; + TempFilename:WideString; + Temp1,Temp2:WideString; + res:bool; +begin + nFO:=0; + FillChar(OpenFileName, SizeOf(OpenFileName), 0); + with OpenFilename do + begin + lStructSize:=SizeOf(OpenFilename); + hWndOwner:=hDlg; + Temp1:= + TranslateWideString('Default extension')+' (*.'+DefExt+')'+#0+'*.'+DefExt+#0+ + TranslateWideString('All files (*.*)')+#0+'*.*'+#0#0; + lpstrFilter:=PWideChar(Temp1); + nMaxFile:=MAX_PATH*16; + SetLength(TempFilename, nMaxFile + 2); + TempFilename[1]:=#0; + lpstrFile :=PWideChar(TempFilename); + Temp2:=TranslateWideString('Choose a file for import...'); + lpstrTitle:=PWideChar(Temp2); + Flags:=flg or OFN_EXPLORER or OFN_ENABLESIZING or OFN_PATHMUSTEXIST or OFN_FILEMUSTEXIST or OFN_NOCHANGEDIR; + end; + res:=GetOpenFileNameW(OpenFileName); + if res then + begin + Result:=TempFilename; + nFO:=OpenFilename.nFileOffset; + end + else Result:=''; +end; + +//***Awkward - author of this procedures************ + +function StrDupW(var dst:PWideChar;src:PWideChar;len:integer=0):PWideChar; +begin + if (src=nil) or (src^=#0) then + dst:=nil + else + begin + if len=0 then + len:=lstrlenw(src); + GetMem(dst,(len+1)*SizeOf(WideChar)); + lstrcpynw(dst,src,len+1); + end; + result:=dst; +end; + +function SelectDirectory(Caption:PWideChar;var Directory:PWideChar; + Parent:HWND=0;newstyle:bool=false):Boolean; +var + BrowseInfo:TBrowseInfoW; + Buffer:array [0..MAX_PATH-1] of WideChar; + ItemIDList:PItemIDList; + ShellMalloc:IMalloc; +begin + Result:=False; + FillChar(BrowseInfo,SizeOf(BrowseInfo),0); + if (ShGetMalloc(ShellMalloc)=S_OK) and (ShellMalloc<>nil) then + begin + with BrowseInfo do + begin + hwndOwner :=Parent; + pszDisplayName:=Buffer; + lpszTitle :=Caption; + ulFlags :=BIF_RETURNONLYFSDIRS; + end; + if newstyle then + if CoInitializeEx(nil,COINIT_APARTMENTTHREADED)<>RPC_E_CHANGED_MODE then + BrowseInfo.ulFlags:=BrowseInfo.ulFlags or BIF_NEWDIALOGSTYLE; + try + ItemIDList:=ShBrowseForFolderW(BrowseInfo); + Result:=ItemIDList<>nil; + if Result then + begin + ShGetPathFromIDListW(ItemIDList,Buffer); + StrDupW(Directory,Buffer); + ShellMalloc.Free(ItemIDList); + end; + finally + if newstyle then CoUninitialize; + end; + end; +end; + +//******************************************************************* + +function FolderDialogExecute(hdlg:HWND; var nFO:integer; const DefExt:string):WideString; //Диалог выбора папки +var + SR: _WIN32_FIND_DATAW; + hFFF:THandle; + tpwc:PWideChar; + tws:WideString; +begin + if SelectDirectory(PWideChar(TranslateWideString('Select folder for import...')),tpwc,hdlg,true) then + begin + result:=tpwc; + result:=result+#0; + nFO:=length(result); + tws:=tpwc; + tws:=tws+'\*.'+DefExt; + SR.dwFileAttributes:=faAnyFile; + hFFF:=FindFirstFileW(PWideChar(tws),SR); + if hFFF<>INVALID_HANDLE_VALUE then + begin + repeat + result:=result+SR.cFileName; + result:=result+#0; + until not FindNextFileW(hFFF,SR); + windows.FindClose(hFFF); + result:=result+#0; + end; + end + else result:=''; +end; + +end. diff --git a/importtxt/General.pas b/importtxt/General.pas new file mode 100644 index 0000000..d263dde --- /dev/null +++ b/importtxt/General.pas @@ -0,0 +1,562 @@ +unit general; + +interface + +uses Windows,Messages,SysUtils,IniFiles, + m_api, + ImportT, + ImportTU; + +var MirVers:DWORD; + IsMirandaUnicode:boolean; + cp:cardinal; + +var + AppPath:array[0..MAX_PATH] of char; + TxtPatterns: array of RTxtPattern; + PatternNames: array of PChar; + PatternsCount:integer; + Protocols:array of TDestProto; + ProtoCount: integer; + CheckForDuplicates:boolean; + ShowDuplicates:boolean; + +const + BIN_PROCEDURE_COUNT=6; //количество реализованых процедур бинарного импорта + +const + {$EXTERNALSYM PBM_SETRANGE} + PBM_SETRANGE = WM_USER+1; + {$EXTERNALSYM PBM_SETPOS} + PBM_SETPOS = WM_USER+2; + +const + IMPORT_TXT_MODULE= 'ImportTXT'; + IMPORT_TXT_SERVICE= IMPORT_TXT_MODULE+'/Import'; + IMPORT_WIZ_SERVICE= IMPORT_TXT_MODULE+'/Wizard'; + + //keys + IMPORT_TXT_AS= 'AutoStart'; + IMPORT_TXT_LP= 'LastPattern'; + +type TOnAccountListChange = procedure (); + +var + OnAccountListChange:TOnAccountListChange; + +function ReadPattern(FileName: string):boolean; +procedure ReadPatterns; +procedure ExtractFilePath(fName:PChar); +function fIsMirandaUnicode:boolean; +function GetContactProto(hContact: THandle): String; +function GetContactByUID(proto:string;id:string):THandle; +function GetContactByNick(Proto:string;Nick:string):THandle; +procedure EnumProtocols; +function GetContactID(hContact: THandle; Proto: String = ''; Contact: boolean = false): String; +function GetContactNick(hContact: THandle; Proto: String = ''; Contact: boolean = false): String; +function DBReadByte (hContact:THANDLE;szModule:PChar;szSetting:PChar;default:byte =0):byte; +function DBWriteByte (hContact:THANDLE;szModule:PChar;szSetting:PChar;val:Byte ):Integer; +procedure SetLastPattern(lp:byte); +function GetLastPattern:byte; +function TimeStampToWStr(ts:dword):WideString; +function StrToTimeStamp(STime:PChar;len:integer):dword; + +function RLWord(adr:integer):word; +function RLInteger(adr:integer):integer; + +implementation + + +procedure ExtractFilePath(fName:PChar); +var p:PChar; +begin + p:=fName; + if p<>nil then + begin + while p^<>#0 do inc(p); + while p^<>'\' do dec(p); + inc(p); + p^:=#0; + end; +end; + +function ReadPattern(FileName: string):boolean; +var TI: TIniFile; + h:integer; + Err:boolean; + tempstr:string; +begin + err:=false; + TI:=TIniFile.Create(FileName); + try + h:=High(TxtPatterns); + if not TI.SectionExists('General') then begin result:=true; exit; end; + //if "General" exists + if TI.ValueExists('General','Name') then TxtPatterns[h].Name:=TI.ReadString('General','Name','') + else err:=true; + if TI.ValueExists('General','Type') then TxtPatterns[h].IType:=TI.ReadInteger('General','Type',1) + else err:=true; + case TxtPatterns[h].IType of + 1: + begin + if TI.ValueExists('General','Charset') then + begin + tempstr:=TI.ReadString('General','Charset','UTF8'); + if tempstr='ANSI' then TxtPatterns[h].Charset:=inANSI + else + if tempstr='UTF8' then TxtPatterns[h].Charset:=inUTF8 + else + if tempstr='UCS2' then TxtPatterns[h].Charset:=inUCS2 + else err:=true; + end + else err:=true; + if TxtPatterns[h].Charset=inANSI then + begin + TxtPatterns[h].Codepage:= TI.ReadInteger('General','Codepage',0); + if not IsValidCodePage(TxtPatterns[h].Codepage) then TxtPatterns[h].Codepage:=0; + end; + TxtPatterns[h].UseHeader:=TI.ReadInteger('General','UseHeader',0); + TxtPatterns[h].UsePreMsg:=TI.ReadBool('General','UsePreMsg',false); + // Read message section + if TI.SectionExists('Message') then + begin + if TI.ValueExists('Message','Pattern') then TxtPatterns[h].Msg.Pattern:=TI.ReadString('Message','Pattern','') + else err:=true; + TxtPatterns[h].Msg.Incoming:=TI.ReadString('Message','In',''); + TxtPatterns[h].Msg.Outgoing:=TI.ReadString('Message','Out',''); + if TI.ValueExists('Message','Direction') then TxtPatterns[h].Msg.Direction:=TI.ReadInteger('Message','Direction',0) + else err:=true; + if TI.ValueExists('Message','Day') then TxtPatterns[h].Msg.Day:=TI.ReadInteger('Message','Day',0) + else err:=true; + if TI.ValueExists('Message','Month') then TxtPatterns[h].Msg.Month:=TI.ReadInteger('Message','Month',0) + else err:=true; + if TI.ValueExists('Message','Year') then TxtPatterns[h].Msg.Year:=TI.ReadInteger('Message','Year',0) + else err:=true; + if TI.ValueExists('Message','Hours') then TxtPatterns[h].Msg.Hours:=TI.ReadInteger('Message','Hours',0) + else err:=true; + if TI.ValueExists('Message','Minutes') then TxtPatterns[h].Msg.Minutes:=TI.ReadInteger('Message','Minutes',0) + else err:=true; + TxtPatterns[h].Msg.Seconds:=TI.ReadInteger('Message','Seconds',0) + end + else err:=true; + // if need read header section + if (TxtPatterns[h].UseHeader>0) then + if TI.SectionExists('Header') then + begin + if TI.ValueExists('Header','Pattern') then TxtPatterns[h].Header.Pattern:=TI.ReadString('Header','Pattern','') + else err:=true; + if (not TI.ValueExists('Header','In')) and ((TxtPatterns[h].UseHeader and 1)=1) then err:=true; + TxtPatterns[h].Header.Incoming:=TI.ReadInteger('Header','In',0); + TxtPatterns[h].Header.Outgoing:=TI.ReadInteger('Header','Out',0); + TxtPatterns[h].Header.InNick:=TI.ReadInteger('Header','InNick',0); + TxtPatterns[h].Header.OutNick:=TI.ReadInteger('Header','OutNick',0); + TxtPatterns[h].Header.InUID:=TI.ReadInteger('Header','InUID',0); + TxtPatterns[h].Header.OutUID:=TI.ReadInteger('Header','OutUID',0); + if ((TxtPatterns[h].UseHeader and 2)=2) then + if (TxtPatterns[h].Header.InNick=0) and (TxtPatterns[h].Header.InUID=0) then err:=true; + end + else err:=true; + // if nead read PreMessage section + if TxtPatterns[h].UsePreMsg then + if TI.SectionExists('PreMessage') then + begin + TxtPatterns[h].PreMsg.PreRN:=TI.ReadInteger('PreMessage','PreRN',-1); + TxtPatterns[h].PreMsg.AfterRN:=TI.ReadInteger('PreMessage','AfterRN',-1); + TxtPatterns[h].PreMsg.PreSP:=TI.ReadInteger('PreMessage','PreSP',0); + TxtPatterns[h].PreMsg.AfterSP:=TI.ReadInteger('PreMessage','AfterSP',0); + end + else err:=true; + end; //1 + 2: + begin + TxtPatterns[h].BinProc:= TI.ReadInteger('General','BinProcedure',0); + if (TxtPatterns[h].BinProc>BIN_PROCEDURE_COUNT) then err:=true; + end; + end; //case + TxtPatterns[h].DefExtension:=TI.ReadString('General','DefaultExtension','txt'); + TxtPatterns[h].UseFileName:=TI.ReadBool('General','UseFileName',false); + // if nead read FileName section + if TxtPatterns[h].UseFileName then + if TI.SectionExists('FileName') then + begin + if TI.ValueExists('FileName','Pattern') then TxtPatterns[h].FName.Pattern:=TI.ReadString('FileName','Pattern','') + else err:=true; + TxtPatterns[h].FName.InNick:=TI.ReadInteger('FileName','InNick',0); + TxtPatterns[h].FName.InUID:=TI.ReadInteger('FileName','InUID',0); + if (TxtPatterns[h].FName.InNick=0) and (TxtPatterns[h].FName.InUID=0) then err:=true; + TxtPatterns[h].FName.OutNick:=TI.ReadInteger('FileName','OutNick',0); + TxtPatterns[h].FName.OutUID:=TI.ReadInteger('FileName','OutUID',0); + end + else err:=true; + finally + TI.Free; + end; + Result:=err; +end; + +procedure ReadPatterns; +var + SR: TSearchRec; + FileAttrs: Integer; + i:integer; +begin + FileAttrs:=faAnyFile; + i:=0; + if FindFirst(AppPath+'\importtxt\*.ini',FileAttrs,SR)=0 then + begin + repeat + SetLength(TxtPatterns,i+1); + SetLength(PatternNames,i+1); + if not ReadPattern(AppPath+'\importtxt\'+SR.Name) then + begin + PatternNames[i]:= PChar(TxtPatterns[i].Name); + inc(i); + end; + until FindNext(SR) <> 0 ; + FindClose(SR); + end; + PatternsCount:=i; +end; + + +function GetContactByUID(proto:string;id:string):THandle; +var + contact:THandle; + otherproto:string; + ci:TCONTACTINFO; + idnum:integer; + tempwstr:PWideChar; + ws:WideString; +begin + if not TryStrToInt(id,idnum) then idnum:=0; + if IsMirandaUnicode then + begin + tempwstr:=UTF8ToWide(PChar(id),tempwstr); + ws :=tempwstr; + FreeMem(tempwstr); + end; + result:=INVALID_HANDLE_VALUE; + contact:=pluginlink^.CallService(MS_DB_CONTACT_FINDFIRST, 0, 0 ); + while (contact<>0) do + begin + otherproto:=PChar(pluginlink^.CallService(MS_PROTO_GETCONTACTBASEPROTO,contact,0)); + if otherproto=proto then + begin + ci.cbSize:=SizeOf(ci); + ci.dwFlag:=CNF_UNIQUEID; + if IsMirandaUnicode then ci.dwFlag:=ci.dwFlag or CNF_UNICODE; + ci.hContact:=contact; + ci.szProto:=PChar(otherproto); + if pluginlink^.CallService(MS_CONTACT_GETCONTACTINFO,0,integer(@ci))=0 then + begin + case ( ci._type ) of + CNFT_BYTE: if ci.retval.bVal = idnum then + begin + result:=contact; + break; + end; + CNFT_WORD: if ci.retval.wVal = idnum then + begin + result:=contact; + break; + end; + CNFT_DWORD: if ci.retval.dVal = DWORD(idnum) then + begin + result:=contact; + break; + end; + CNFT_ASCIIZ: + if IsMirandaUnicode then + if ws=ci.retval.szVal.w then + begin + result:=contact; + break; + end else + else + if id=ci.retval.szVal.a then + begin + result:=contact; + break; + end; + end; //case + end; //if + end; //if + contact:= Pluginlink^.CallService(MS_DB_CONTACT_FINDNEXT,contact,0); + end; //while +end; + +function GetContactByNick(Proto:string;Nick:string):THandle; +var + contact:THandle; + otherproto:string; + ci:TCONTACTINFO; + tempwstr:PWideChar; + ws:WideString; +begin + if IsMirandaUnicode then + begin + tempwstr:=UTF8ToWide(PChar(Nick),tempwstr); + ws :=tempwstr; + FreeMem(tempwstr); + end; + result:=INVALID_HANDLE_VALUE; + contact:=pluginlink^.CallService(MS_DB_CONTACT_FINDFIRST, 0, 0 ); + while (contact<>0) do + begin + otherproto:=PChar(pluginlink^.CallService(MS_PROTO_GETCONTACTBASEPROTO,contact,0)); + if otherproto=proto then + begin + ci.cbSize:=SizeOf(ci); + ci.dwFlag:=CNF_NICK; + if IsMirandaUnicode then ci.dwFlag:=ci.dwFlag or CNF_UNICODE; + ci.hContact:=contact; + ci.szProto:=PChar(otherproto); + if pluginlink^.CallService(MS_CONTACT_GETCONTACTINFO,0,integer(@ci))=0 then + begin + if IsMirandaUnicode then + begin + if ws=ci.retval.szVal.w then + begin + result:=contact; + break; + end; + end + else + begin + if Nick=ci.retval.szVal.a then + begin + result:=contact; + break; + end; + end; + end; //if + end; //if + contact:= Pluginlink^.CallService(MS_DB_CONTACT_FINDNEXT,contact,0); + end; //while +end; + +procedure EnumProtocols; +var i,iProtoCount:integer; + ppAccounts:^PPROTOACCOUNT; + temps:string; +begin + ProtoCount:=0; + SetLength(Protocols,30); + if MirVers> $080000 then pluginLink^.CallService(MS_PROTO_ENUMACCOUNTS,int(@iProtoCount),int(@ppAccounts)) + else pluginLink^.CallService(MS_PROTO_ENUMPROTOCOLS,int(@iProtoCount),int(@ppAccounts)); + for i:=1 to iProtoCount do + begin + if (ppAccounts^^._type=PROTOTYPE_PROTOCOL) then + begin + temps:=GetContactID(0,ppAccounts^^.szModuleName,false); + if temps<>'' then + begin + protocols[ProtoCount].ProtoName:=ppAccounts^^.szModuleName; + protocols[ProtoCount].ProtoUID:=temps; + protocols[ProtoCount].ProtoNick:=GetContactNick(0,ppAccounts^^.szModuleName,false); + inc(ProtoCount); + end; + end; + inc(ppAccounts); + end; + SetLength(Protocols,ProtoCount); +end; + +function fIsMirandaUnicode:boolean; +var ver:ShortString; +begin + Result:=true; + SetLength(ver,255); + if PluginLink.CallService(MS_SYSTEM_GETVERSIONTEXT,wParam(255),lParam(@ver[1]))=0 then + Result:=Pos('Unicode',ver)>0; +end; + +function GetContactProto(hContact: THandle): String; +begin + Result := PChar(PluginLink.CallService(MS_PROTO_GETCONTACTBASEPROTO,hContact,0)); +end; + +function DBFreeVariant(dbv:PDBVARIANT):integer; +begin + Result:=PluginLink^.CallService(MS_DB_CONTACT_FREEVARIANT,0,lParam(dbv)); +end; + +function GetContactID(hContact: THandle; Proto: String = ''; Contact: boolean = false): String; +var + uid: PChar; + dbv: TDBVARIANT; + cgs: TDBCONTACTGETSETTING; + tempstr:PChar; +begin + Result := ''; + if not ((hContact = 0) and Contact) then begin + if Proto = '' then Proto := GetContactProto(hContact); + uid := PChar(CallProtoService(PChar(Proto),PS_GETCAPS,PFLAG_UNIQUEIDSETTING,0)); + if (Cardinal(uid) <> CALLSERVICE_NOTFOUND) and (uid <> nil) then begin + cgs.szModule := PChar(Proto); + cgs.szSetting := uid; + cgs.pValue := @dbv; + if PluginLink^.CallService(MS_DB_CONTACT_GETSETTING,hContact,LPARAM(@cgs)) = 0 then begin + case dbv._type of + DBVT_BYTE: + Result := intToStr(dbv.bVal); + DBVT_WORD: + Result := intToStr(dbv.wVal); + DBVT_DWORD: + Result := intToStr(dbv.dVal); + DBVT_ASCIIZ: + if IsMirandaUnicode then + begin + tempstr:=ANSIToUTF8(dbv.szVal.a,tempstr,cp); + Result :=tempstr; + FreeMem(tempstr); + end else Result := dbv.szVal.a; + DBVT_UTF8: + if IsMirandaUnicode then Result :=dbv.szVal.a + else + begin + tempstr:=UTF8ToANSI(dbv.szVal.a,tempstr,cp); + Result :=tempstr; + FreeMem(tempstr); + end; + DBVT_WCHAR: + begin + if IsMirandaUnicode then tempstr:=WideToUTF8(dbv.szVal.w,tempstr) + else tempstr:=WideToAnsi(dbv.szVal.w,tempstr,cp); + Result:=tempstr; + FreeMem(tempstr); + end; + end; + // free variant + DBFreeVariant(@dbv); + end; + end; + end; +end; + +function GetContactNick(hContact: THandle; Proto: String = ''; Contact: boolean = false): String; +var + dbv: TDBVARIANT; + cgs: TDBCONTACTGETSETTING; + tempstr:PChar; +begin + Result := ''; + if not ((hContact = 0) and Contact) then begin + if Proto = '' then Proto := GetContactProto(hContact); + cgs.szModule := PChar(Proto); + cgs.szSetting := 'Nick'; + cgs.pValue := @dbv; + if PluginLink^.CallService(MS_DB_CONTACT_GETSETTING,hContact,LPARAM(@cgs)) = 0 then begin + case dbv._type of + DBVT_BYTE: + Result := intToStr(dbv.bVal); + DBVT_WORD: + Result := intToStr(dbv.wVal); + DBVT_DWORD: + Result := intToStr(dbv.dVal); + DBVT_ASCIIZ: + if IsMirandaUnicode then + begin + tempstr:=ANSIToUTF8(dbv.szVal.a,tempstr,cp); + Result :=tempstr; + FreeMem(tempstr); + end else Result := dbv.szVal.a; + DBVT_UTF8: + if IsMirandaUnicode then Result :=dbv.szVal.a + else + begin + tempstr:=UTF8ToANSI(dbv.szVal.a,tempstr,cp); + Result :=tempstr; + FreeMem(tempstr); + end; + DBVT_WCHAR: + begin + if IsMirandaUnicode then tempstr:=WideToUTF8(dbv.szVal.w,tempstr) + else tempstr:=WideToAnsi(dbv.szVal.w,tempstr,cp); + Result:=tempstr; + FreeMem(tempstr); + end; + end; + // free variant + DBFreeVariant(@dbv); + end; + end; +end; + +function DBReadByte(hContact:THANDLE;szModule:PChar;szSetting:PChar;default:byte=0):byte; +var + dbv:TDBVARIANT; + cgs:TDBCONTACTGETSETTING; +begin + cgs.szModule :=szModule; + cgs.szSetting:=szSetting; + cgs.pValue :=@dbv; + If PluginLink^.CallService(MS_DB_CONTACT_GETSETTING,hContact,lParam(@cgs))<>0 then + Result:=default + else + Result:=dbv.bVal; +end; + +function DBWriteByte(hContact:THANDLE;szModule:PChar;szSetting:PChar;val:Byte):Integer; +var + cws:TDBCONTACTWRITESETTING; +begin + cws.szModule :=szModule; + cws.szSetting :=szSetting; + cws.value._type:=DBVT_BYTE; + cws.value.bVal :=Val; + Result:=PluginLink^.CallService(MS_DB_CONTACT_WRITESETTING,hContact,lParam(@cws)); +end; + +procedure SetLastPattern(lp:byte); +begin + DBWriteByte(0,IMPORT_TXT_MODULE,IMPORT_TXT_LP,lp); +end; + +function GetLastPattern:byte; +begin + result:=DBReadByte(0,IMPORT_TXT_MODULE,IMPORT_TXT_LP,0); + if result>=PatternsCount then result:=0; +end; + +function TimeStampToWStr(ts:dword):WideString; +var dbtts:TDBTIMETOSTRING; + s:WideString; +begin + SetLength(s,20); + dbtts.szFormat.w:='d s'; + dbtts.szDest.w:=PWideChar(s); + dbtts.cbDest:=20; + pluginlink^.CallService(MS_DB_TIME_TIMESTAMPTOSTRINGT,ts,Int(@dbtts)); + result:=s; +end; + +function StrToTimeStamp(STime:PChar;len:integer):dword; +var hour, min, sec, day, month, year: integer; +begin + sec:=0; + day:=(ord(stime[0])-$30)*10+(ord(stime[1])-$30); + month:=(ord(stime[3])-$30)*10+(ord(stime[4])-$30); + year:=(ord(stime[6])-$30)*1000+(ord(stime[7])-$30)*100+(ord(stime[8])-$30)*10+(ord(stime[9])-$30); + hour:=(ord(stime[11])-$30)*10+(ord(stime[12])-$30); + min:=(ord(stime[14])-$30)*10+(ord(stime[15])-$30); + if len>15 then sec:=(ord(stime[17])-$30)*10+(ord(stime[18])-$30); + result:=Timestamp(year,month,day,hour,min,sec); +end; + +function RLWord(adr:integer):word; +begin + Result:=PByte(adr+1)^ + (PByte(adr)^ *$100); +end; + +function RLInteger(adr:integer):integer; +begin + Result:=PByte(adr+3)^ + (PByte(adr+2)^*$100) + + (PByte(adr+1)^ * $10000) + (PByte(adr)^ *$1000000); +end; + +begin + GetModuleFileName(hInstance,@AppPath[0],MAX_PATH); + ExtractFilePath(AppPath); + ReadPatterns; +end. diff --git a/importtxt/ImpDlgRes.inc b/importtxt/ImpDlgRes.inc new file mode 100644 index 0000000..b176adb --- /dev/null +++ b/importtxt/ImpDlgRes.inc @@ -0,0 +1,12 @@ +const + IDD_IMPDIALOG = 101; + IDSTART = 1001; + IDC_FILENAME = 1002; + IDC_BRWSBTN = 1003; + IDC_TYPECOMBO = 1004; + IDC_STATUSLIST = 1005; + IDC_PROGRESS = 1006; + IDC_CHKDUP = 1007; + IDC_SHOWDUP = 1008; + + IDI_DEFAULT = 110; \ No newline at end of file diff --git a/importtxt/ImpTxtDlg.rc b/importtxt/ImpTxtDlg.rc new file mode 100644 index 0000000..e1f3b19 --- /dev/null +++ b/importtxt/ImpTxtDlg.rc @@ -0,0 +1,18 @@ +101 DIALOGEX 0, 0, 264, 220 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Import history to " +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +FONT 8, "MS Shell Dlg" +BEGIN + PUSHBUTTON "Start",1001,2,204,50,14 + PUSHBUTTON "Close",IDCLOSE,211,204,50,14 + LTEXT "Choose a file...",1002,3,3,240,11,SS_SUNKEN + PUSHBUTTON "...",1003,244,3,17,11 + COMBOBOX 1004,3,16,258,80,CBS_DROPDOWNLIST | CBS_DISABLENOSCROLL | WS_VSCROLL | WS_TABSTOP + LISTBOX 1005,3,42,258,150,LBS_NOINTEGRALHEIGHT | LBS_NOSEL | WS_VSCROLL | WS_TABSTOP + CONTROL "",1006,"msctls_progress32",0x1,3,194,258,8 + CHECKBOX "Check for duplicates", 1007, 3, 29, 105, 12, BS_AUTOCHECKBOX | WS_VISIBLE | WS_TABSTOP + CHECKBOX "Show duplicates", 1008, 140, 29, 86, 12, BS_AUTOCHECKBOX | WS_VISIBLE | WS_TABSTOP +END + +110 ICON "ico\def_ico.ico" \ No newline at end of file diff --git a/importtxt/ImpTxtDlg.res b/importtxt/ImpTxtDlg.res new file mode 100644 index 0000000..9feb9a0 Binary files /dev/null and b/importtxt/ImpTxtDlg.res differ diff --git a/importtxt/ImpTxtWiz.rc b/importtxt/ImpTxtWiz.rc new file mode 100644 index 0000000..617c23a --- /dev/null +++ b/importtxt/ImpTxtWiz.rc @@ -0,0 +1,64 @@ + +102 DIALOGEX 0, 0, 220, 143 +STYLE DS_SETFONT | DS_FIXEDSYS | DS_CENTER | WS_CAPTION | WS_SYSMENU +CAPTION "Import Text Files Wizard" +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +FONT 8, "MS Shell Dlg" +BEGIN + DEFPUSHBUTTON "&Next >",IDOK,120,124,45,13 + PUSHBUTTON "Cancel",IDCANCEL,168,124,45,13 + PUSHBUTTON "< &Back",3,75,124,45,13 + CONTROL "",1011,"Static",SS_ETCHEDHORZ,5,116,210,1 +END + +103 DIALOGEX 0, 0, 220, 114 +STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | DS_CONTROL | WS_CHILD +FONT 8, "MS Shell Dlg" +BEGIN + LTEXT "This wizard will help you import message history from some other clients and Miranda plugins, stored in text files.",1010,18,12,182,32 + LTEXT "Click ""Next"" to choose the information you wish to import, or click ""Cancel"" to exit the wizard and continue using Miranda.",1009,18,42,182,25 + CTEXT "It is recommended that you create a backup of your current Miranda profile before importing.",1008,18,78,182,21 +END + +104 DIALOGEX 0, 0, 220, 114 +STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | DS_CONTROL | WS_CHILD +FONT 8, "MS Shell Dlg" +BEGIN + LTEXT "Choose type of imported files:",1010,6,76,208,8 + COMBOBOX 1007,5,90,208,30,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP +END + +105 DIALOGEX 0, 0, 220, 114 +STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | DS_CONTROL | WS_CHILD +FONT 8, "MS Shell Dlg" +BEGIN + LTEXT "Select files or the whole directory for import:",1010,6,86,208,8 + LISTBOX 1002,5,12,208,55,LBS_SORT | LBS_NOINTEGRALHEIGHT | LBS_NOSEL | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Files...",1001,157,96,56,14 + LTEXT "Path:",1009,6,73,24,8 + EDITTEXT 1003,31,71,182,12,ES_AUTOHSCROLL | WS_DISABLED + LTEXT "Files:",1008,6,3,208,8 + PUSHBUTTON "Directory...",1005,101,96,56,14 +END + +106 DIALOGEX 0, 0, 220, 114 +STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | DS_CONTROL | WS_CHILD +FONT 8, "MS Shell Dlg" +BEGIN + CHECKBOX "Check messages for duplicates", 1012, 6, 20, 140, 14, BS_AUTOCHECKBOX | WS_VISIBLE | WS_TABSTOP + CHECKBOX "Show duplicates", 1013, 6, 32, 86, 14, BS_AUTOCHECKBOX | WS_VISIBLE | WS_TABSTOP + LTEXT "All previous chosen files will try to import to this protocol.", 1010, 6, 46, 208, 10 + COMBOBOX 1007,5,66,208,30,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + LTEXT "Select protocol or account:",1009,6,55,208,8 + CTEXT "Click ""Next"" to start Import or ""Cancel"" to Abort.",1008,6,96,208,8 +END + +107 DIALOGEX 0, 0, 220, 114 +STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | DS_CONTROL | WS_CHILD +FONT 8, "MS Shell Dlg" +BEGIN + LTEXT "Now importing...",1010,6,11,208,8 + CONTROL "Progress1",1004,"msctls_progress32",WS_BORDER | 0x1,5,24,208,10 + LISTBOX 1006,5,38,208,61,NOT LBS_NOTIFY | LBS_NOINTEGRALHEIGHT | LBS_DISABLENOSCROLL | LBS_NOSEL | WS_VSCROLL | WS_TABSTOP +END + diff --git a/importtxt/ImpTxtWiz.res b/importtxt/ImpTxtWiz.res new file mode 100644 index 0000000..2164f8e Binary files /dev/null and b/importtxt/ImpTxtWiz.res differ diff --git a/importtxt/ImpTxt_Ver.rc b/importtxt/ImpTxt_Ver.rc new file mode 100644 index 0000000..df41863 --- /dev/null +++ b/importtxt/ImpTxt_Ver.rc @@ -0,0 +1,28 @@ +1 VERSIONINFO +FILEVERSION 0,0,1,10 +PRODUCTVERSION 0,0,1,10 +FILEOS 0x4 +FILETYPE 0x2 +{ +BLOCK "StringFileInfo" +{ + BLOCK "000004b0" + { + VALUE "CompanyName", "Miranda Open Source Project" + VALUE "FileDescription", "ImportTXT plugin for Miranda IM" + VALUE "FileVersion", "0.0.1.10" + VALUE "InternalName", "importtxt" + VALUE "LegalCopyright", "© 2008 Abyss" + VALUE "LegalTrademarks", "Gnu General Public License V2" + VALUE "OriginalFilename", "importtxt.dll" + VALUE "ProductName", "Import TXT Module" + VALUE "ProductVersion", "0.0.1.10" + VALUE "Comments", "Imports history saved in TXT files from other clients" + } +} + +BLOCK "VarFileInfo" +{ + VALUE "Translation", 0x0000 0x04B0 +} +} diff --git a/importtxt/ImpTxt_Ver.res b/importtxt/ImpTxt_Ver.res new file mode 100644 index 0000000..3a97a11 Binary files /dev/null and b/importtxt/ImpTxt_Ver.res differ diff --git a/importtxt/ImpWizRes.inc b/importtxt/ImpWizRes.inc new file mode 100644 index 0000000..a60bba6 --- /dev/null +++ b/importtxt/ImpWizRes.inc @@ -0,0 +1,21 @@ +const + IDC_BACK = 3; + IDD_IMPWIZARD = 102; + IDD_IMPWIZARDINTRO = 103; + IDD_IMPTYPE = 104; + IDD_IMPFILES = 105; + IDD_IMPDEST = 106; + IDD_PROGRESS = 107; + IDC_FILE = 1001; + IDC_LIST = 1002; + IDC_PATH = 1003; + IDC_PROGRESS = 1004; + IDC_DIR = 1005; + IDC_STATUS = 1006; + IDC_COMBO1 = 1007; + IDC_STATIC3 = 1008; + IDC_STATIC2 = 1009; + IDC_STATIC1 = 1010; + IDC_STATIC = 1011; + IDC_CHKDUPW = 1012; + IDC_SHOWDUPW = 1013; diff --git a/importtxt/ImportT.pas b/importtxt/ImportT.pas new file mode 100644 index 0000000..4976d2c --- /dev/null +++ b/importtxt/ImportT.pas @@ -0,0 +1,82 @@ +unit ImportT; +interface + +type + + RHeader = record + Pattern:string; + Incoming:integer; + Outgoing:integer; + InNick:integer; + OutNick:integer; + InUID:integer; + OutUID:integer; + end; + + RPreMessage = record + PreRN:integer; + AfterRN:integer; + PreSP:integer; + AfterSP:integer; + end; + + RMessage = record + Pattern:string; + Incoming:string; + Outgoing:string; + Direction:integer; + Day:integer; + Month:integer; + Year:integer; + Hours:integer; + Minutes:integer; + Seconds:integer; + end; + + RFileName = record + Pattern:string; + InNick:integer; + OutNick:integer; + InUID:integer; + OutUID:integer; + end; + + RTxtPattern = record + Name:string; + IType:byte; //1 -text,2- binary, 3 - ... + Charset:word; + Codepage:Cardinal; + DefExtension:string; + BinProc:word; + UseHeader:Byte; + UseFileName:ByteBool; + UsePreMsg:ByteBool; + Msg:RMessage; + Header:RHeader; + PreMsg:RPreMessage; + FName:RFileName; + end; + +const + inANSI = 1; + inUTF8 = 2; + inUCS2 = 3; + +type PDestProto = ^TDestProto; + TDestProto = record + ProtoName: string; + ProtoUID: string; + ProtoNick: string; + end; + +type PDestContact = ^TDestContact; + TDestContact = record + hContact: THandle; + ProtoName: string; + ContactUID: string; + ContactNick: string; + end; + +implementation + +end. diff --git a/importtxt/ImportTU.pas b/importtxt/ImportTU.pas new file mode 100644 index 0000000..1ef7bdd --- /dev/null +++ b/importtxt/ImportTU.pas @@ -0,0 +1,260 @@ +Unit ImportTU; + +interface + +Uses windows, StrUtils, + m_api; + +type + PDayTable = ^TDayTable; + TDayTable = array[1..12] of Word; + +const + MonthDays: array [Boolean] of TDayTable = + ((31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31), + (31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)); + +function Timestamp(Year,Month,Day,Hour,Min,Sec:Word; toGMT:boolean = true):LongWord; +{function TimestampICQ(Year,Month,Day,Hour,Min,Sec:Word):LongWord;} +function DateTimeToTimeStamp(const DateTime: TDateTime; toGMT: boolean = true): DWord; + + + +{***** Authtor of this procedures Alexey Kulakov aka Awkward*****} +function ChangeUnicode(str:PWideChar):PWideChar; +function UTF8Len(src:PChar):integer; +function WideToANSI(src:PWideChar;var dst:PChar ;cp:dword=CP_ACP):PChar; +function ANSIToWide(src:PChar ;var dst:PWideChar;cp:dword=CP_ACP):PWideChar; +function ANSIToUTF8(src:PChar ;var dst:pChar ;cp:dword=CP_ACP):PChar; +function UTF8toANSI(src:PChar ;var dst:PChar ;cp:dword=CP_ACP):PChar; +function UTF8toWide(src:PChar ;var dst:PWideChar;len:cardinal=dword(-1)):PWideChar; +function WidetoUTF8(src:PWideChar;var dst:PChar ):PChar; +{*****} + + +implementation + +uses SysUtils; + +function IsLeapYear(Year:Word):Boolean; +begin + Result:=(Year mod 4=0) and ((Year mod 100<>0) or (Year mod 400=0)); +end; + +function Timestamp(Year,Month,Day,Hour,Min,Sec:Word; toGMT: boolean = true):LongWord; +var i:Integer; + DayTable:PDayTable; + DT,D:Longword; +begin + //fix for 2 digit year + if year>0 then + if year<90 then inc(year,2000) + else + if year <100 then inc(year,1900); + // + DayTable:=@MonthDays[IsLeapYear(Year)]; + for i:=1 to Month-1 do Inc(Day,DayTable^[i]); + I := Year - 1; + D := I * 365 + I div 4 - I div 100 + I div 400 + Day - (1969*365 + 492 - 19 + 4 +1); + DT:= (D*24*60*60) + (Hour*3600+Min*60+Sec); + //Приводим к GMT...судя по всему миранда хранит таймштампы в GMT + if toGMT then Result := DT -(PluginLink.CallService(MS_DB_TIME_TIMESTAMPTOLOCAL,DT,0)-DT) + else Result := DT; +end; + +function DateTimeToTimeStamp(const DateTime: TDateTime; toGMT: boolean = true): DWord; +begin + Result := Round((DateTime-UnixDateDelta) * SecsPerDay); + if toGMT then Result := Result -(PluginLink.CallService(MS_DB_TIME_TIMESTAMPTOLOCAL,Result,0)-Result); +end; + +function ChangeUnicode(str:PWideChar):PWideChar; +var + i,len:integer; +begin + result:=str; + if str=nil then + exit; + if (word(str^)=$FFFE) or (word(str^)=$FEFF) then + begin + len:=lstrlenw(str); + if word(str^)=$FFFE then + begin + i:=len-1; + while i>0 do // str^<>#0 + begin + pword(str)^:=swap(pword(str)^); + inc(str); + dec(i); + end; +// str:=result; + end; + move((result+1)^,result^,len*SizeOf(WideChar)); + end; +end; + +function WideToANSI(src:PWideChar;var dst:PChar; cp:dword=CP_ACP):PChar; +var + len,l:integer; +begin + if (src=nil) or (src^=#0) then + begin + GetMem(dst,1); + dst^:=#0; + end + else + begin + l:=lstrlenw(src); + len:=WideCharToMultiByte(cp,0,src,l,NIL,0,NIL,NIL)+1; + GetMem(dst,len); + FillChar(dst^,len,0); + WideCharToMultiByte(cp,0,src,l,dst,len,NIL,NIL); + end; + result:=dst; +end; + +function ANSIToWide(src:PChar;var dst:PWideChar; cp:dword=CP_ACP):PWideChar; +var + len,l:integer; +begin + if (src=nil) or (src^=#0) then + begin + GetMem(dst,SizeOf(WideChar)); + dst^:=#0; + end + else + begin + l:=lstrlen(src); + len:=MultiByteToWideChar(cp,0,src,l,NIL,0)+1; + GetMem(dst,len*SizeOf(WideChar)); + FillChar(dst^,len*SizeOf(WideChar),0); + MultiByteToWideChar(cp,0,src,l,dst,len); + end; + result:=dst; +end; + +function ANSIToUTF8(src:PChar;var dst:pChar;cp:dword=CP_ACP):PChar; +var + tmp:PWideChar; +begin + AnsiToWide(src,tmp,cp); + result:=WideToUTF8(tmp,dst); + FreeMem(tmp); +end; + +function UTF8Len(src:PChar):integer; // w/o zero +begin + result:=0; + if src<>nil then + begin + while src^<>#0 do + begin + if (ord(src^) and $80)=0 then + else if (ord(src^) and $E0)=$E0 then + inc(src,2) + else + inc(src); + inc(result); + inc(src); + end; + end; +end; + +function CalcUTF8Len(src:pWideChar):integer; +begin + result:=0; + if src<>nil then + begin + while src^<>#0 do + begin + if src^<#$0080 then + else if src^<#$0800 then + inc(result) + else + inc(result,2); + inc(src); + inc(result); + end; + end; +end; + +function UTF8toWide(src:PChar; var dst:PWideChar; len:cardinal=dword(-1)):PWideChar; +var + w:word; + p:PWideChar; +begin + GetMem(dst,(UTF8Len(src)+1)*SizeOf(WideChar)); + p:=dst; + if src<>nil then + begin + while (src^<>#0) and (len>0) do + begin + if ord(src^)<$80 then + w:=ord(src^) + else if (ord(src^) and $E0)=$E0 then + begin + w:=(ord(src^) and $1F) shl 12; + inc(src); dec(len); + w:=w or (((ord(src^))and $3F) shl 6); + inc(src); dec(len); + w:=w or (ord(src^) and $3F); + end + else + begin + w:=(ord(src^) and $3F) shl 6; + inc(src); dec(len); + w:=w or (ord(src^) and $3F); + end; + p^:=WideChar(w); + inc(p); + inc(src); dec(len); + end; + end; + p^:=#0; + result:=dst; +end; + +function UTF8toANSI(src:PChar;var dst:PChar;cp:dword=CP_ACP):PChar; +var + tmp:pWideChar; +begin + UTF8ToWide(src,tmp); + result:=WideToAnsi(tmp,dst,cp); + FreeMem(tmp); +end; + +function WidetoUTF8(src:PWideChar; var dst:PChar):PChar; +var + p:PChar; +begin + GetMem(dst,CalcUTF8Len(src)+1); + p:=dst; + if src<>nil then + begin + while src^<>#0 do + begin + if src^<#$0080 then + p^:=Char(src^) + else if src^<#$0800 then + begin + p^:=chr($C0 or (ord(src^) shr 6)); + inc(p); + p^:=chr($80 or (ord(src^) and $3F)); + end + else + begin + p^:=chr($E0 or (ord(src^) shr 12)); + inc(p); + p^:=chr($80 or ((ord(src^) shr 6) and $3F)); + inc(p); + p^:=chr($80 or (ord(src^) and $3F)); + end; + inc(p); + inc(src); + end; + end; + p^:=#0; + result:=dst; +end; + +end. diff --git a/importtxt/ImportThrd.pas b/importtxt/ImportThrd.pas new file mode 100644 index 0000000..4da1eae --- /dev/null +++ b/importtxt/ImportThrd.pas @@ -0,0 +1,599 @@ +unit ImportThrd; + +interface + +uses + Classes, + Windows, + SysUtils, + StrUtils, + PerlRegEx, + m_api, + general, + ImportT, + ImportTU, + KOLEdb + ; + + + +const ITXT_THREAD_BASE = $8000+$2000;//WM_APP + $2000 + ITXT_THREAD_START = ITXT_THREAD_BASE+1; //Поток запустился (0,0) + ITXT_THREAD_MAXPROGRESS = ITXT_THREAD_BASE+2; // Мах прогресс (0, MaxProgress) + ITXT_THREAD_PROGRESS = ITXT_THREAD_BASE+3; //Прогресс (Current, 0) + ITXT_THREAD_ERROR = ITXT_THREAD_BASE+4; //Возникла ошибка (PWideChar(ErrorString),0) + ITXT_THREAD_FINISH = ITXT_THREAD_BASE+5; //Завершение файла, подведение результатов (Added, Duplicates) + ITXT_THREAD_START_FILE = ITXT_THREAD_BASE+6; //Начали работать с файлом(PWideChar(FileName),0); + ITXT_THREAD_DEST_CONTACT = ITXT_THREAD_BASE+7; //Определили контакт (hContact,0) + ITXT_THREAD_ALLSTARTED = ITXT_THREAD_BASE+8; //Началось + ITXT_THREAD_ALLFINISHED = ITXT_THREAD_BASE+9; //Всё закончено :) + +type + TSendMethod = (smSend,smPost); + +type + TImportThrd = class(TThread) + private + { Private declarations } + RegExpr:TPerlRegEx; + hMapedFile:THandle; + hFile:THandle; + pFileText:Pointer; + FolderName:WideString; + FileName:WideString; + FileLen:Cardinal; + fContact:TDestContact; //Contact recognised by filename + AddedMessages: integer; + Duplicates: integer; + function DoMessage(Message: Longword; wParam: WPARAM; lParam: LPARAM; Method: TSendMethod = smSend): Boolean; + function DoMapFile:boolean; + procedure DoUnMapFile; + Procedure PreMessageSP(var src:string; CSP:integer); + procedure AddMsgToDB(hContact:Thandle; Direction:integer; MsgTimeStamp:LongWord; const Text: string; + var AddMsg,Dupy:integer); + procedure TextImportProcedure; + procedure BinImportProcedure; + protected + procedure Execute; override; + public + FileNames:WideString; //File Names + OffsetFileName:integer; //offset name of file in FileNames + WorkPattern:RTxtPattern; // Pattern for work + DContact:TDestContact; //Recognised or defined contact + Destination:TDestProto; // destination protocol + ParentHWND:LongWord; //HWND of parent window + end; + + +function IsDuplicateEvent(hContact:THandle; dbei:TDBEVENTINFO):boolean; + +function PassMessage(Handle: THandle; Message: LongWord; wParam: WPARAM; lParam: LPARAM; Method: TSendMethod = smSend): Boolean; + + +implementation + + +// Returns TRUE if event already is in base +function IsDuplicateEvent(hContact:THandle; dbei:TDBEVENTINFO):boolean; +var + hExistingDbEvent:THandle; + dbeiExisting:TDBEVENTINFO; + dwFirstEventTimeStamp:LongWord; + dwLastEventTimeStamp:LongWord; + dwPreviousTimeStamp:LongWord; +begin + result:=FALSE; + if not CheckForDuplicates then exit; + hExistingDbEvent:=pluginLink^.CallService(MS_DB_EVENT_FINDFIRST, hContact, 0); + if hExistingDbEvent=0 then begin Result:=False; exit; end; + + FillChar(dbeiExisting, SizeOf(dbeiExisting), Byte(0)); + dbeiExisting.cbSize:= sizeof(dbeiExisting); + dbeiExisting.cbBlob:= 0; + pluginLink^.CallService(MS_DB_EVENT_GET, wParam(hExistingDbEvent), lParam(@dbeiExisting)); + dwFirstEventTimeStamp:=dbeiExisting.timestamp; + + hExistingDbEvent:=pluginLink^.CallService(MS_DB_EVENT_FINDLAST, wParam(hContact), lParam(0)); + if hExistingDbEvent=0 then begin Result:=False; exit; end; + + FillChar(dbeiExisting, SizeOf(dbeiExisting), Byte(0)); + dbeiExisting.cbSize:= sizeof(dbeiExisting); + dbeiExisting.cbBlob:= 0; + pluginLink^.CallService(MS_DB_EVENT_GET, wParam(hExistingDbEvent), lParam(@dbeiExisting)); + dwLastEventTimeStamp:=dbeiExisting.timestamp; + + // If before the first + if (dbei.timestamp < dwFirstEventTimeStamp) then begin Result:=False; exit; end; + + // If after the last + if (dbei.timestamp > dwLastEventTimeStamp) then begin Result:=False; exit; end; + + dwPreviousTimeStamp:=dwLastEventTimeStamp; + + if (dbei.timestamp <= dwPreviousTimeStamp) then // search from the end + begin + while (hExistingDbEvent <> 0) do + begin + FillChar(dbeiExisting, SizeOf(dbeiExisting), Byte(0)); + dbeiExisting.cbSize:= sizeof(dbeiExisting); + dbeiExisting.cbBlob:= 0; + pluginLink^.CallService(MS_DB_EVENT_GET, wParam(hExistingDbEvent), lParam(@dbeiExisting)); + // compare event + if ( dbei.timestamp = dbeiExisting.timestamp ) and + ( (dbei.flags) = (dbeiExisting.flags and not DBEF_FIRST)) and //fix for first event + (dbei.eventType = dbeiExisting.eventType) and + (dbei.cbBlob = dbeiExisting.cbBlob) then begin Result:=true; exit; end; + + if (dbei.timestamp > dbeiExisting.timestamp) then begin Result:=False; exit; end; + // get the previous + hExistingDbEvent:=pluginLink^.CallService(MS_DB_EVENT_FINDPREV, wParam(hExistingDbEvent), 0); + end; + end; +end; + + +Procedure TImportThrd.PreMessageSP(var src:string; CSP:integer); +var i:integer; + ls:integer; + PSP,ASP:integer; +begin + ls:=-1; + repeat + i:=ls+2; + PSP:=0; + while (src[i+PSP]=' ') do inc(PSP); + if PSP>0 then + case WorkPattern.PreMsg.PreSP of + 0: PSP:=0; + -1: ; + -2: if PSP>CSP then PSP:=CSP; + else if PSP>WorkPattern.PreMsg.PreSP then PSP:=WorkPattern.PreMsg.PreSP; + end; //case + Delete(src,i,PSP); + ls:=PosEx(#$0D#$0A,src,i); + ASP:=0; + while (ls>1) and (src[ls-ASP-1]=' ') do inc(ASP); + if ASP>0 then + case WorkPattern.PreMsg.AfterSP of + 0: ASP:=0; + -1: ; + -2: if ASP>CSP then ASP:=CSP; + else if ASP>WorkPattern.PreMsg.AfterSP then ASP:=WorkPattern.PreMsg.AfterSP; + end; //case + Delete(src,ls-ASP-1,ASP); + Until ls<=0 +end; + +Procedure TImportThrd.AddMsgToDB(hContact:Thandle; Direction:integer;MsgTimeStamp:LongWord; const Text: string; + var AddMsg,Dupy:integer); +var dbei:TDBEVENTINFO; + proto:string; + s:WideString; +begin + FillChar(dbei, SizeOf(dbei), Byte(0)); + dbei.cbSize:= sizeof(dbei); + dbei.eventType:= EVENTTYPE_MESSAGE; + dbei.flags:=direction; + proto:=GetContactProto(hContact); + dbei.szModule:= PAnsiChar(proto); + dbei.timestamp:=MsgTimeStamp; + dbei.cbBlob:=Length(Text)+1; + dbei.pBlob:=PByte(AllocMem(dbei.cbBlob)); + try + Move(Text[1],dbei.pBlob^,dbei.cbBlob); + if not IsDuplicateEvent(hContact,dbei) then + if pluginLink^.CallService(MS_DB_EVENT_ADD, wParam(hContact), lParam(@dbei))<>0 then Inc(AddMsg) + else begin + s:= 'Error adding message to DB'; + DoMessage(ITXT_THREAD_ERROR,integer(PWideChar(s)),0); end + + else + begin + if ShowDuplicates then + begin + if (dbei.flags and DBEF_SENT)>0 then s:='>' + else s:='<'; + s:=TranslateWideString('Duplicate:')+' '+s+' '+TimeStampToWStr(dbei.timestamp); + DoMessage(ITXT_THREAD_ERROR,integer(PWideChar(s)),0,smSend); + end; + Inc(Dupy); + end; + finally + FreeMem(dbei.pBlob); + end; +end; + +function PassMessage(Handle: THandle; Message: LongWord; wParam: WPARAM; lParam: LPARAM; Method: TSendMethod = smSend): Boolean; +var + Tries: integer; +begin + Result := True; + case Method of + smSend: SendMessage(Handle,Message,wParam,lParam); + smPost: begin + Tries := 5; + while (Tries > 0) and not PostMessage(Handle,Message,wParam,lParam) do begin + Dec(Tries); + Sleep(5); + end; + Result := (Tries > 0); + end; + end; +end; + +function TImportThrd.DoMessage(Message: LongWord; wParam: WPARAM; lParam: LPARAM; Method: TSendMethod = smSend): Boolean; +begin + Result := PassMessage(ParentHWND,Message,wParam,lParam,Method); +end; + +function TImportThrd.DoMapFile:boolean; +var s:WideString; +begin + result:=true; + hFile:=CreateFileW(PWideChar(FileName),GENERIC_READ,0,nil,OPEN_EXISTING,0,0); + if hFile=INVALID_HANDLE_VALUE then + begin + result:=false; + s:='Error opening file'; + DoMessage(ITXT_THREAD_ERROR,integer(PWideChar(s)),0); + exit; + end; + FileLen:=GetFileSize(hFile,nil); + hMapedFile:=CreateFileMapping(hFile,nil,PAGE_READONLY,0,0,'ImportTXTmapfile'); + if hMapedFile=0 then + begin + result:=false; + s:= 'Error mapping file'; + DoMessage(ITXT_THREAD_ERROR,integer(PWideChar(s)),0); + exit; + end; + pFileText:=MapViewOfFile(hMapedFile,FILE_MAP_READ,0,0,0); + if pFileText=nil then + begin + result:=false; + s:='Error mapping'; + DoMessage(ITXT_THREAD_ERROR,integer(PWideChar(s)),0); + exit; + end; +end; + +procedure TImportThrd.DoUnMapFile; +begin + UnmapViewOfFile(pFileText); + pFileText:=nil; + CloseHandle(hMapedFile); + CloseHandle(hFile); +end; + +procedure TryDetermContact(var dContact:TDestContact); +begin + if dContact.ProtoName<>'' then + begin + if dContact.ContactUID<>'' then + begin + dContact.hContact:=GetContactByUID(dContact.ProtoName,dContact.ContactUID) + end + else + if dContact.ContactNick<>'' then + begin + dContact.hContact:=GetContactByNick(dContact.ProtoName,dContact.ContactNick); + end + else + dContact.hContact:=INVALID_HANDLE_VALUE; + end + else + dContact.hContact:=INVALID_HANDLE_VALUE; +end; + +procedure TImportThrd.TextImportProcedure; +var + PosCur,LenCur,PosNext:integer; + TextLength, + h1,h2:integer; + PRN,ARN,j:DWORD; + msg_flag:integer; + DT:LongWord; + TxtMsg:string; + s:WideString; + tempstr:PChar; + tempwstr:PWideChar; +begin + AddedMessages:=0; + Duplicates:=0; + Case WorkPattern.Charset of + inANSI:if IsMirandaUnicode then + begin + if WorkPattern.Codepage<>0 then tempstr:=ANSIToUTF8(PAnsiChar(pFileText),tempstr,WorkPattern.Codepage) + else tempstr:=ANSIToUTF8(PAnsiChar(pFileText),tempstr,cp); + RegExpr.Subject:=tempstr; + FreeMem(tempstr); + end + else RegExpr.Subject:=PAnsiChar(pFileText); + inUTF8:if IsMirandaUnicode then RegExpr.Subject:=PChar(pFileText)+3 + else + begin + tempstr:=UTF8ToANSI(PChar(pFileText)+3,tempstr,cp); + RegExpr.Subject:=tempstr; + FreeMem(tempstr); + end; + inUCS2:begin + GetMem(tempwstr,FileLen+2); + lstrcpynW(tempwstr,PWideChar(pFileText),FileLen); + tempwstr[FileLen div SizeOf(WideChar)]:=#$0000; //file is not ended dy #0000 + if IsMirandaUnicode then tempstr:=WidetoUTF8(ChangeUnicode(tempwstr),tempstr) + else tempstr:=WideToANSI(ChangeUnicode(tempwstr),tempstr,cp); + RegExpr.Subject:=tempstr; + FreeMem(tempstr); + FreeMem(tempwstr); + end; + end; //case + if (WorkPattern.UseHeader and 1)=0 then //If the information on a direction is not present that we will transform a line + begin + if IsMirandaUnicode then + begin + tempstr:=ANSIToUTF8(PAnsiChar(WorkPattern.Msg.Incoming),tempstr,cp); + WorkPattern.Msg.Incoming:=tempstr; + FreeMem(tempstr); + tempstr:=ANSIToUTF8(PAnsiChar(WorkPattern.Msg.Outgoing),tempstr,cp); + WorkPattern.Msg.Outgoing:=tempstr; + FreeMem(tempstr); + end + end; + if (WorkPattern.UseHeader>0) then + begin + if IsMirandaUnicode then + begin + tempstr:=ANSIToUTF8(PAnsiChar(WorkPattern.Header.Pattern),tempstr,cp); + RegExpr.RegEx:=tempstr; + RegExpr.Options:=[preMultiLine, preUTF8]; + FreeMem(tempstr); + end + else + begin + RegExpr.RegEx:=WorkPattern.Header.Pattern; + RegExpr.Options:=[preMultiLine]; + end; + if not RegExpr.Match then + begin + s:=TranslateWideString('Header not found'); + DoMessage(ITXT_THREAD_ERROR,integer(PWideChar(s)),0); + exit; + end + else + begin + if (WorkPattern.UseHeader and 1)=1 then + begin + WorkPattern.Msg.Incoming:=RegExpr.SubExpressions[WorkPattern.Header.Incoming]; + WorkPattern.Msg.Outgoing:=RegExpr.SubExpressions[WorkPattern.Header.Outgoing]; + end; + if (WorkPattern.UseHeader and 2)=2 then + if (DContact.hContact=0) or (DContact.hContact=INVALID_HANDLE_VALUE) then + begin + if WorkPattern.Header.InUID<>0 then DContact.ContactUID:=RegExpr.SubExpressions[WorkPattern.Header.InUID] + else DContact.ContactUID:=''; + if WorkPattern.Header.InNick<>0 then DContact.ContactNick:=RegExpr.SubExpressions[WorkPattern.Header.InNick] + else DContact.ContactNick:=''; + TryDetermContact(DContact); + end; + end; + end; + //Whether if it has not turned out to define in header then we look it was defined in a file + if (DContact.hContact=0) or (DContact.hContact=INVALID_HANDLE_VALUE) then + if (fContact.hContact<>0) and (fContact.hContact<>INVALID_HANDLE_VALUE) then + DContact:=fContact; + if (DContact.hContact<>0) and (DContact.hContact<>INVALID_HANDLE_VALUE) then + begin + DoMessage(ITXT_THREAD_DEST_CONTACT,DContact.hContact,0); + DoMessage(ITXT_THREAD_START,0,0); + if IsMirandaUnicode then + begin + tempstr:=ANSIToUTF8(PAnsiChar(WorkPattern.Msg.Pattern),tempstr,cp); + RegExpr.RegEx:=tempstr; + RegExpr.Options:=[preMultiLine, preUTF8]; + FreeMem(tempstr); + end + else + begin + RegExpr.RegEx:=WorkPattern.Msg.Pattern; + RegExpr.Options:=[preMultiLine]; + end; + + TextLength:=Length(RegExpr.Subject)-1; //Position of last symbol + DoMessage(ITXT_THREAD_MAXPROGRESS,0,TextLength); + RegExpr.State:=[preNotEmpty]; + //search for regular expression + if not RegExpr.Match then + begin + s:=TranslateWideString('No messages in this file'); + DoMessage(ITXT_THREAD_ERROR,integer(PWideChar(s)),0); + end + else + begin + PosCur:=RegExpr.MatchedExpressionOffset; //get the position of RegExpression + repeat + LenCur:=RegExpr.MatchedExpressionLength; //get the length of RegExpression + //Further we define a message direction (incoming or outgoing) + if RegExpr.SubExpressions[WorkPattern.Msg.Direction]=WorkPattern.Msg.Incoming then msg_flag:=DBEF_READ + else msg_flag:=DBEF_READ or DBEF_SENT; + if IsMirandaUnicode then msg_flag:=msg_flag or DBEF_UTF; + //make timestamp + if WorkPattern.Msg.Seconds<>0 then + DT:=TimeStamp( + StrToInt(RegExpr.SubExpressions[WorkPattern.Msg.Year]), + StrToInt(RegExpr.SubExpressions[WorkPattern.Msg.Month]), + StrToInt(RegExpr.SubExpressions[WorkPattern.Msg.Day]), + StrToInt(RegExpr.SubExpressions[WorkPattern.Msg.Hours]), + StrToInt(RegExpr.SubExpressions[WorkPattern.Msg.Minutes]), + StrToInt(RegExpr.SubExpressions[WorkPattern.Msg.Seconds]) + ) else + DT:=TimeStamp( + StrToInt(RegExpr.SubExpressions[WorkPattern.Msg.Year]), + StrToInt(RegExpr.SubExpressions[WorkPattern.Msg.Month]), + StrToInt(RegExpr.SubExpressions[WorkPattern.Msg.Day]), + StrToInt(RegExpr.SubExpressions[WorkPattern.Msg.Hours]), + StrToInt(RegExpr.SubExpressions[WorkPattern.Msg.Minutes]), + 0 + ); + + if RegExpr.MatchAgain then PosNext:=RegExpr.MatchedExpressionOffset //search for next regexpr + else PosNext:=TextLength; // if not then end of file + h1:=PosCur+LenCur; //The message text beginning presumably + h2:=PosNext-PosCur-LenCur-2; //its presumably message length + //working with message text + if WorkPattern.UsePreMsg then PRN:=DWORD(WorkPattern.PreMsg.PreRN) + else PRN:=DWORD(-1); + if PRN<>0 then + begin + j:=1; + while ((RegExpr.Subject[h1]=Char($0D))and + (RegExpr.Subject[h1+1]=Char($0A))) and + (j<=PRN) + do begin inc(h1,2); dec(h2,2); inc(j); end; //remove carriage return in the beginning + end; + if WorkPattern.UsePreMsg then ARN:=DWORD(WorkPattern.PreMsg.AfterRN) + else ARN:=DWORD(-1); + if ARN<>0 then + begin + j:=1; + while ((RegExpr.Subject[h1+h2]=Char($0D))and + (RegExpr.Subject[h1+h2+1]=Char($0A))) and + (j<=ARN) + do begin dec(h2,2); inc(j) end; //remove carriage return in the end + end; + //get the message text + TxtMsg:=Copy(RegExpr.Subject,h1,h2+2); + //remove spaces if needs + if WorkPattern.UsePreMsg and ((WorkPattern.PreMsg.PreSP<>0) or (WorkPattern.PreMsg.AfterSP<>0)) then + if IsMirandaUnicode then PreMessageSP(TxtMsg,UTF8Len(PChar(RegExpr.MatchedExpression))) + else PreMessageSP(TxtMsg,LenCur); + AddMsgToDB(DContact.hContact,msg_flag,DT,TxtMsg,AddedMessages,Duplicates); //adding in base + PosCur:=PosNext; + DoMessage(ITXT_THREAD_PROGRESS,PosCur,0); + until (PosNext = TextLength) or Terminated ; + end; //RegExpr.Exec + end + else + begin + s:=TranslateWideString('Can''t determine destination contact'); + DoMessage(ITXT_THREAD_ERROR,integer(PWideChar(s)),0); + end; +end; + +procedure TImportThrd.BinImportProcedure; +var i:integer; + s:WideString; + tempstr:PChar; +var dbei:TDBEVENTINFO; + proto:string; + pt:integer; + fsz:integer; + +{$define BIN_IMPORT_} +{$i BmContactIP.inc} +{$i BqhfIP.inc} +{$i BICQ6IP.inc} +{$i BICQ5IP.inc} +{$i BRMSIP.inc} +{$i BbayanIP.inc} +{$undef BIN_IMPORT_} +begin + AddedMessages:=0; + Duplicates:=0; + case WorkPattern.BinProc of + 1: //mContactImport + {$i BmContactIP.inc} + 2: //QHF + {$i BqhfIP.inc} + 3: //ICQ6 + {$i BICQ6IP.inc} + 4: //ICQ5 + {$i BICQ5IP.inc} + 5: //Nokia midp-rms + {$i BRMSIP.inc} + 6: //BayanICQ + {$i BbayanIP.inc} + + end; +end; + +procedure TImportThrd.Execute; +var + i:integer; + s1:WideString; + tempstr:PChar; +begin + DoMessage(ITXT_THREAD_ALLSTARTED,0,0); + FolderName:=Copy(FileNames,1,OffsetFileName-1); + i:=OffsetFileName; + while (FileNames[i+1]<>#0)and not Terminated do + begin //начало цикла по файлам + s1:=''; + Inc(i); + while FileNames[i]<>#0 do + begin s1:=s1+FileNames[i]; inc(i); end; + if (s1<>'') and (s1<>#0) then + begin //Начинаем работать с файлом + FileName:=FolderName+'\'+s1; + DoMessage(ITXT_THREAD_START_FILE,Integer(PWideChar(FileName)),0,smSend); + pFileText:=nil; + hFile:=INVALID_HANDLE_VALUE; + DContact.ProtoName:=Destination.ProtoName; + fContact.hContact:=INVALID_HANDLE_VALUE; + RegExpr:=TPerlRegEx.Create; //Создаём объект для работы с рег. выражениями + try + //Поработаем с именем файла + if WorkPattern.UseFileName then + if (DContact.hContact=0) or (DContact.hContact=INVALID_HANDLE_VALUE) then + begin + if IsMirandaUnicode then + begin + tempstr:=WideToUTF8(PWideChar(FileName),tempstr); + RegExpr.Subject:=tempstr; + FreeMem(tempstr); + tempstr:=ANSIToUTF8(PAnsiChar(WorkPattern.FName.Pattern),tempstr,cp); + RegExpr.RegEx:=tempstr; + FreeMem(tempstr); + RegExpr.Options:=[preUTF8]; + end + else + begin + RegExpr.Subject:=FileName; + RegExpr.RegEx:=WorkPattern.FName.Pattern; + RegExpr.Options:=[]; + end; + if RegExpr.Match then + begin + fContact.ProtoName:=Destination.ProtoName; + if WorkPattern.FName.InUID<>0 then fContact.ContactUID:=RegExpr.SubExpressions[WorkPattern.FName.InUID] + else fContact.ContactUID:=''; + if WorkPattern.FName.InNick<>0 then fContact.ContactNick:=RegExpr.SubExpressions[WorkPattern.FName.InNick] + else fContact.ContactNick:=''; + TryDetermContact(fContact); + end; + end; + + //Загружаем сам файл + // [preMultiLine] модификатор для восприятия многострочного текста + if DoMapFile then //Загружаем файл + begin + pluginLink^.CallService(MS_DB_SETSAFETYMODE, wParam(false), 0); + case WorkPattern.IType of + 1:TextImportProcedure; + 2:BinImportProcedure; + end; //case + end; //DoMapFile + finally + pluginLink^.CallService(MS_DB_SETSAFETYMODE, wParam(true), 0); + DoMessage(ITXT_THREAD_FINISH,AddedMessages,Duplicates); + DoUnMapFile; + RegExpr.Free; + end; + DContact.hContact:=INVALID_HANDLE_VALUE; + Sleep(10); //чтобы все сообщения дошли до окна + end; //закончили работать с файлом + end; //цикла по файлам + DoMessage(ITXT_THREAD_ALLFINISHED,0,0); +end; + +end. + \ No newline at end of file diff --git a/importtxt/ImportTxtWiz.pas b/importtxt/ImportTxtWiz.pas new file mode 100644 index 0000000..72c74b2 --- /dev/null +++ b/importtxt/ImportTxtWiz.pas @@ -0,0 +1,369 @@ +unit ImportTxtWiz; + +interface + +uses Windows,Messages,SysUtils, + m_api, + general, ImportTU, FileDlgs, + ImportThrd + ; + +{$R ImpTxtWiz.res} +{$I ImpWizRes.inc} + +const + WIZM_GOTOPAGE = (WM_USER+10); //wParam=resource id, lParam=dlgproc + WIZM_DISABLEBUTTON = (WM_USER+11); //wParam=0:back, 1:next, 2:cancel + WIZM_SETCANCELTEXT = (WM_USER+12); //lParam=(char*)newText + WIZM_SETNEXTTEXT = (WM_USER+13); //lParam=(char*)newText + WIZM_ENABLEBUTTON = (WM_USER+14); //wParam=0:back, 1:next, 2:cancel + + WIZM_ACCLISTCHANGED = (WM_USER+15); //OnAccountListChanged + +var hwndPage:HWND; + IndexOfPattern:integer; + FileNames:array of WideString; + FileName:string; + nFO:integer; + FilePath:WideString; + ProtoSelect: integer; + ImportThrd:TImportThrd; + StartTime,FinishTime:TDateTime; + +function WizardIntroPageProc(hdlg:HWND; hMessage,wParam,lParam:DWORD):LongBool; stdcall; +function ImportTypePageProc(hdlg:HWND; hMessage,wParam,lParam:DWORD):LongBool; stdcall; +function WizardDlgProc(hdlg:HWND; hMessage,wParam,lParam:DWORD):LongBool; stdcall; +function ImportFilesPageProc(hdlg:HWND; hMessage,wParam,lParam:DWORD):LongBool; stdcall; +function ImportDestinationPageProc(hdlg:HWND; hMessage,wParam,lParam:DWORD):LongBool; stdcall; +function ImportProgressPageProc(hdlg:HWND; hMessage,wParam,lParam:DWORD):LongBool; stdcall; + +implementation + + +function MakeFileList(hdlg:HWND; param:WORD):boolean; +var i:integer; + s1:WideString; +begin + result:=false; + case param of + IDC_FILE: FileName:=OpenDialogExecute(hdlg, $0200, nFO,TxtPatterns[IndexOfPattern].DefExtension); //OFN_ALLOWMULTISELECT = $00000200; + IDC_DIR: FileName:=FolderDialogExecute(hdlg, nFO,TxtPatterns[IndexOfPattern].DefExtension); + end; + if FileName<>'' then + begin + SendDlgItemMessageW(hDlg,IDC_LIST,LB_RESETCONTENT,0,0); + SendDlgItemMessageW(hdlg, IDC_PATH,WM_SETTEXT,0,0); + SetLength(FileNames,0); + FilePath:=Copy(FileName,1,nFO-1); + SendDlgItemMessageW(hdlg, IDC_PATH,WM_SETTEXT,0,dword(PWideChar(FilePath))); + i:=nFO; + while FileName[i+1]<>#0 do + begin + s1:=''; + Inc(i); + while FileName[i]<>#0 do + begin s1:=s1+FileName[i]; inc(i); end; + if (s1<>'') and (s1<>#0) then + begin + SetLength(FileNames,Length(FileNames)+1); + FileNames[High(FileNames)]:=s1; + SendDlgItemMessageW(hDlg,IDC_LIST,LB_ADDSTRING,0,Integer(PWideChar(s1))); + end; + end; + end; + if High(FileNames)>-1 then result:=true; +end; + +procedure AddStatusMessage(hDLG:HWND; msg:WideString); +begin + SendDlgItemMessageW(hDLG,IDC_STATUS,LB_SETCURSEL,SendDlgItemMessageW(hDLG,IDC_STATUS,LB_ADDSTRING,0,dword(PWideChar(msg))),0); +end; + +procedure AccLstChngd; +begin + SendMessageW(hwndPage,WIZM_ACCLISTCHANGED,0,0); +end; + +function WizardIntroPageProc(hdlg:HWND; hMessage,wParam,lParam:DWORD):LongBool; stdcall; +begin + result:=false; + case hMessage of + WM_INITDIALOG: + begin + TranslateDialogDefault(hdlg); + SendMessage(GetParent(hdlg), WIZM_DISABLEBUTTON, 0, 0); + IndexOfPattern:=0; + ProtoSelect:=0; + SetLength(FileNames,0); + result:=true; + end; + WM_COMMAND: + case LOWORD(wParam) of + IDOK: + PostMessage(GetParent(hdlg), WIZM_GOTOPAGE, IDD_IMPTYPE, integer(@ImportTypePageProc)); + IDCANCEL: + PostMessage(GetParent(hdlg), WM_CLOSE, 0, 0); + end; //Case wParam + end; //Case hMassege +end; + +function ImportTypePageProc(hdlg:HWND; hMessage,wParam,lParam:DWORD):LongBool; stdcall; +var i:integer; +begin + result:=false; + case hMessage of + WM_INITDIALOG: + begin + TranslateDialogDefault(hdlg); + ReadPatterns; + if PatternsCount>0 then + begin + For i:=0 to PatternsCount-1 do + SendDlgItemMessage(hDlg,IDC_COMBO1,CB_ADDSTRING,0,Integer(PatternNames[i])); + SendDlgItemMessage(hDlg, IDC_COMBO1, CB_SETCURSEL, GetLastPattern, 0); + IndexOfPattern:=GetLastPattern; + end + else + SendMessage(GetParent(hdlg), WIZM_DISABLEBUTTON, 1, 0); + result:=true; + end; + WM_COMMAND: + begin + if (HiWord(wParam)=CBN_SELCHANGE) and (LoWord(wParam)=IDC_COMBO1) then + IndexOfPattern:=SendDlgItemMessage(hdlg, IDC_COMBO1, CB_GETCURSEL, 0, 0); + Case LOWORD(wParam) of + IDC_BACK: + PostMessage(GetParent(hdlg), WIZM_GOTOPAGE, IDD_IMPWIZARDINTRO, integer(@WizardIntroPageProc)); + IDOK: + PostMessage(GetParent(hdlg), WIZM_GOTOPAGE, IDD_IMPFILES, integer(@ImportFilesPageProc)); + IDCANCEL: + PostMessage(GetParent(hdlg), WM_CLOSE, 0, 0); + end; //Case wParam + end; //WM_COMMAND + end; //Case hMassage +end; + +function ImportFilesPageProc(hdlg:HWND; hMessage,wParam,lParam:DWORD):LongBool; stdcall; +var i:integer; +begin + result:=false; + case hMessage of + WM_INITDIALOG: + begin + TranslateDialogDefault(hdlg); + if High(FileNames)<0 then SendMessage(GetParent(hdlg), WIZM_DISABLEBUTTON, 1, 0) + else + begin + SendDlgItemMessageW(hdlg, IDC_PATH,WM_SETTEXT,0,dword(PWideChar(FilePath))); + for i:=0 to High(FileNames) do + SendDlgItemMessageW(hDlg,IDC_LIST,LB_ADDSTRING,0,Integer(PWideChar(FileNames[i]))); + end; + result:=true; + end; + WM_COMMAND: + Case LOWORD(wParam) of + IDC_FILE, + IDC_DIR: if MakeFileList(hdlg,LOWORD(wParam)) then SendMessage(GetParent(hdlg), WIZM_ENABLEBUTTON, 1, 0) + else SendMessage(GetParent(hdlg), WIZM_DISABLEBUTTON, 1, 0); + IDC_BACK: + PostMessage(GetParent(hdlg), WIZM_GOTOPAGE, IDD_IMPTYPE, integer(@ImportTypePageProc)); + IDOK: + PostMessage(GetParent(hdlg), WIZM_GOTOPAGE, IDD_IMPDEST, integer(@ImportDestinationPageProc)); + IDCANCEL: + PostMessage(GetParent(hdlg), WM_CLOSE, 0, 0); + end; //Case wParam + end; //Case hMassage +end; + +function ImportDestinationPageProc(hdlg:HWND; hMessage,wParam,lParam:DWORD):LongBool; stdcall; +var i:integer; + tempws:WideString; +begin + result:=false; + case hMessage of + WM_INITDIALOG: + begin + TranslateDialogDefault(hdlg); + EnumProtocols; + for i:=0 to ProtoCount-1 do + begin + tempws:=Protocols[i].ProtoName+' | '; + if IsMirandaUnicode then tempws:=tempws+UTF8Decode(Protocols[i].ProtoUID)+' | '+UTF8Decode(Protocols[i].ProtoNick) + else tempws:=tempws+Protocols[i].ProtoUID+' | '+Protocols[i].ProtoNick; + SendDlgItemMessageW(hDlg,IDC_COMBO1,CB_ADDSTRING,0,Integer(PWideChar(tempws))); + end; + SendDlgItemMessage(hDlg, IDC_COMBO1, CB_SETCURSEL, 0, 0); + OnAccountListChange:=AccLstChngd; + CheckDlgButton(hdlg,IDC_CHKDUPW,BST_CHECKED); + CheckForDuplicates:=true; + CheckDlgButton(hdlg,IDC_SHOWDUPW,BST_UNCHECKED); + CheckForDuplicates:=false; + result:=true; + end; + WM_COMMAND: begin + if (HiWord(wParam)=CBN_SELCHANGE) and (LoWord(wParam)=IDC_COMBO1) then + ProtoSelect:=SendDlgItemMessage(hdlg, IDC_COMBO1, CB_GETCURSEL, 0, 0); + if (HiWord(wParam)=BN_CLICKED) and (LoWord(wParam)=IDC_CHKDUPW) then + if LongBool(IsDlgButtonChecked(hdlg,IDC_CHKDUPW)) then EnableWindow(GetDlgItem(hdlg, IDC_SHOWDUPW), TRUE) + else EnableWindow(GetDlgItem(hdlg, IDC_SHOWDUPW), FALSE); + Case LOWORD(wParam) of + IDC_BACK: + PostMessage(GetParent(hdlg), WIZM_GOTOPAGE, IDD_IMPFILES, integer(@ImportFilesPageProc)); + IDOK:begin + CheckForDuplicates:=LongBool(IsDlgButtonChecked(hdlg,IDC_CHKDUPW)); + ShowDuplicates:=LongBool(IsDlgButtonChecked(hdlg,IDC_SHOWDUPW)); + PostMessage(GetParent(hdlg), WIZM_GOTOPAGE, IDD_PROGRESS, integer(@ImportProgressPageProc));end; + IDCANCEL: + PostMessage(GetParent(hdlg), WM_CLOSE, 0, 0); + end; //Case wParam + end; //WM_COMMAND + WIZM_ACCLISTCHANGED:begin + ProtoSelect:=SendDlgItemMessage(hdlg, IDC_COMBO1, CB_GETCURSEL, 0, 0); + SendDlgItemMessageW(hDlg,IDC_COMBO1,CB_RESETCONTENT,0,0); + for i:=0 to ProtoCount-1 do + begin + tempws:=Protocols[i].ProtoName+' | '; + if IsMirandaUnicode then tempws:=tempws+UTF8Decode(Protocols[i].ProtoUID)+' | '+UTF8Decode(Protocols[i].ProtoNick) + else tempws:=tempws+Protocols[i].ProtoUID+' | '+Protocols[i].ProtoNick; + SendDlgItemMessageW(hDlg,IDC_COMBO1,CB_ADDSTRING,0,Integer(PWideChar(tempws))); + end; + if ProtoSelect Case insensitive + preMultiLine, // /m -> ^ and $ also match before/after a newline, not just at the beginning and the end of the string + preSingleLine, // /s -> Dot matches any character, including \n (newline). Otherwise, it matches anything except \n + preExtended, // /x -> Allow regex to contain extra whitespace, newlines and Perl-style comments, all of which will be filtered out + preAnchored, // /A -> Successful match can only occur at the start of the subject or right after the previous match + preDollarEndOnly, // /E + preExtra, // /X + preUnGreedy, // Repeat operators (+, *, ?) are not greedy by default + // (i.e. they try to match the minimum number of characters instead of the maximum) + preUTF8 // UTF8 + ); +type + TPerlRegExState = set of ( + preNotBOL, // Not Beginning Of Line: ^ does not match at the start of Subject + preNotEOL, // Not End Of Line: $ does not match at the end of Subject + preNotEmpty // Empty matches not allowed + ); + +const + // Maximum number of subexpressions (backreferences) + // Subexpressions are created by placing round brackets in the regex, and are referenced by \1, \2, ... + // In Perl, they are available as $1, $2, ... after the regex matched; with TPerlRegEx, use the Subexpressions property + // You can also insert \1, \2, ... in the Replacement string; \0 is the complete matched expression + MAX_SUBEXPRESSIONS = 99; + + +type + TPerlRegEx = class + private // *** Property storage, getters and setters + FCompiled, FStudied: Boolean; + FOptions: TPerlRegExOptions; + FState: TPerlRegExState; + FRegEx, FSubject: string; + FStart, FStop: Integer; + function GetMatchedExpression: string; + function GetMatchedExpressionLength: Integer; + function GetMatchedExpressionOffset: Integer; + procedure SetOptions(Value: TPerlRegExOptions); + procedure SetRegEx(const Value: string); + function GetSubExpressionCount: Integer; + function GetSubExpressions(Index: Integer): string; + function GetSubExpressionLengths(Index: Integer): Integer; + function GetSubExpressionOffsets(Index: Integer): Integer; + procedure SetSubject(const Value: string); + procedure SetStart(const Value: Integer); + procedure SetStop(const Value: Integer); + function GetFoundMatch: Boolean; + private // *** Variables used by pcrelib.dll + Offsets: array[0..(MAX_SUBEXPRESSIONS+1)*3] of Integer; + OffsetCount: Integer; + pcreOptions: Integer; + pattern, hints, chartable: Pointer; + FSubjectPChar: PChar; + protected + procedure CleanUp; + // Dispose off whatever we created, so we can start over. Called automatically when needed, so it is not made public + public + constructor Create; + // Come to life + destructor Destroy; override; + // Clean up after ourselves + class function EscapeRegExChars(const S: string): string; + // Escapes regex characters in S so that the regex engine can be used to match S as plain text + procedure Compile; + // Compile the regex. Called automatically by Match + procedure Study; + // Study the regex. Studying takes time, but will make the execution of the regex a lot faster. + // Call study if you will be using the same regex many times + function Match: Boolean; + // Attempt to match the regex + function MatchAgain: Boolean; + // Attempt to match the regex to the remainder of the string after the previous match + // To avoid problems (when using ^ in the regex), call MatchAgain only after a succesful Match() + function NamedSubExpression(const SEName: string): Integer; + // Returns the index of the named group SEName + function Config (What: integer): Integer; + //This function makes it possible for a client program + // to find out which optional features are available in the + //version of the PCRE library it is using. + property Compiled: Boolean read FCompiled; + // True if the RegEx has already been compiled. + property FoundMatch: Boolean read GetFoundMatch; + // Returns True when MatchedExpression* and SubExpression* indicate a match + property Studied: Boolean read FStudied; + // True if the RegEx has already been studied + property MatchedExpression: string read GetMatchedExpression; + // The matched string + property MatchedExpressionLength: Integer read GetMatchedExpressionLength; + // Length of the matched string + property MatchedExpressionOffset: Integer read GetMatchedExpressionOffset; + // Character offset in the Subject string at which the matched substring starts + property Start: Integer read FStart write SetStart; + // Starting position in Subject from which MatchAgain begins + property Stop: Integer read FStop write SetStop; + // Last character in Subject that Match and MatchAgain search through + property State: TPerlRegExState read FState write FState; + // State of Subject + property SubExpressionCount: Integer read GetSubExpressionCount; + // Number of matched subexpressions + property SubExpressions[Index: Integer]: string read GetSubExpressions; + // Matched subexpressions after a regex has been matched + property SubExpressionLengths[Index: Integer]: Integer read GetSubExpressionLengths; + // Lengths of the subexpressions + property SubExpressionOffsets[Index: Integer]: Integer read GetSubExpressionOffsets; + // Character offsets in the Subject string of the subexpressions + property Subject: string read FSubject write SetSubject; + // The string on which Match() will try to match RegEx + published + property Options: TPerlRegExOptions read FOptions write SetOptions; + // Options + property RegEx: string read FRegEx write SetRegEx; + // The regular expression to be matched + end; + + + +implementation + + { ********* pcrelib.dll imports ********* } + +const + PCRE_CASELESS = $00000001; + PCRE_MULTILINE = $00000002; + PCRE_SINGLELINE = $00000004; + PCRE_EXTENDED = $00000008; + PCRE_ANCHORED = $00000010; + PCRE_DOLLAR_ENDONLY = $00000020; + PCRE_EXTRA = $00000040; + PCRE_NOTBOL = $00000080; + PCRE_NOTEOL = $00000100; + PCRE_UNGREEDY = $00000200; + PCRE_NOTEMPTY = $00000400; + PCRE_UTF8 = $00000800; + PCRE_NO_AUTO_CAPTURE = $00001000; + PCRE_NO_UTF8_CHECK = $00002000; + PCRE_AUTO_CALLOUT = $00004000; + PCRE_PARTIAL = $00008000; + PCRE_DFA_SHORTEST = $00010000; + PCRE_DFA_RESTART = $00020000; + PCRE_FIRSTLINE = $00040000; + PCRE_DUPNAMES = $00080000; + PCRE_NEWLINE_CR = $00100000; + PCRE_NEWLINE_LF = $00200000; + PCRE_NEWLINE_CRLF = $00300000; + PCRE_NEWLINE_ANY = $00400000; + + // Exec error codes + PCRE_ERROR_NOMATCH = -1; + PCRE_ERROR_NULL = -2; + PCRE_ERROR_BADOPTION = -3; + PCRE_ERROR_BADMAGIC = -4; + PCRE_ERROR_UNKNOWN_OPCODE = -5; + PCRE_ERROR_UNKNOWN_NODE = -5; // For backward compatibility + PCRE_ERROR_NOMEMORY = -6; + PCRE_ERROR_NOSUBSTRING = -7; + PCRE_ERROR_MATCHLIMIT = -8; + PCRE_ERROR_CALLOUT = -9; // Never used by PCRE itself + PCRE_ERROR_BADUTF8 =-10; + PCRE_ERROR_BADUTF8_OFFSET =-11; + PCRE_ERROR_PARTIAL =-12; + PCRE_ERROR_BADPARTIAL =-13; + PCRE_ERROR_INTERNAL =-14; + PCRE_ERROR_BADCOUNT =-15; + PCRE_ERROR_DFA_UITEM =-16; + PCRE_ERROR_DFA_UCOND =-17; + PCRE_ERROR_DFA_UMLIMIT =-18; + PCRE_ERROR_DFA_WSSIZE =-19; + PCRE_ERROR_DFA_RECURSE =-20; + PCRE_ERROR_RECURSIONLIMIT =-21; + PCRE_ERROR_NULLWSLIMIT =-22; + PCRE_ERROR_BADNEWLINE =-23; + +(* Request types for pcre_config(). Do not re-arrange, in order to remain compatible. *) + + PCRE_CONFIG_UTF8 = 0; + PCRE_CONFIG_NEWLINE = 1; + PCRE_CONFIG_LINK_SIZE = 2; + PCRE_CONFIG_POSIX_MALLOC_THRESHOLD = 3; + PCRE_CONFIG_MATCH_LIMIT = 4; + PCRE_CONFIG_STACKRECURSE = 5; + PCRE_CONFIG_UNICODE_PROPERTIES = 6; + PCRE_CONFIG_MATCH_LIMIT_RECURSION = 7; +type + PPChar = ^PChar; + PInt = ^Integer; + + + +// Functions we import from the PCRE library DLL +// Leading underscores gratuitously added by Borland C++Builder 6.0 +function pcre_maketables: PAnsiChar; cdecl; external 'pcre3.dll'; +function pcre_compile(const pattern: PChar; options: Integer; errorptr: PPChar; erroroffset: PInt; + const tables: PChar): Pointer; cdecl; external 'pcre3.dll'; +function pcre_exec(const pattern: Pointer; const hints: Pointer; const subject: PChar; length, startoffset: Integer; + options: Integer; offsets: PInt; offsetcount: Integer): Integer; cdecl; external 'pcre3.dll'; +function pcre_get_stringnumber(const pattern: Pointer; const Name: PChar): Integer; cdecl; external 'pcre3.dll'; +function pcre_study(const pattern: Pointer; options: Integer; errorptr: PPChar): Pointer; cdecl; external 'pcre3.dll'; +function pcre_fullinfo(const pattern: Pointer; const hints: Pointer; what: Integer; where: Pointer): Integer; cdecl; external 'pcre3.dll'; +function pcre_version: pchar; cdecl; external 'pcre3.dll'; +function pcre_config (what:integer; where:pointer):integer; cdecl; external 'pcre3.dll'; +//procedure pcre_free(ptr: Pointer); cdecl; external 'pcre3.dll'; + + + + + { ********* TPerlRegEx component ********* } + +procedure TPerlRegEx.CleanUp; +begin + FCompiled := False; FStudied := False; + pattern := nil; hints := nil; + OffsetCount := 0; +end; + +procedure TPerlRegEx.Compile; +var + Error: PChar; + ErrorOffset: Integer; +begin + if FRegEx = '' then raise Exception.Create('TPerlRegEx.Compile() - Please specify a regular expression in RegEx first'); + CleanUp; + Pattern := pcre_compile(PChar(FRegEx), pcreOptions, @Error, @ErrorOffset, chartable); + if Pattern = nil then + raise Exception.Create(Format('TPerlRegEx.Compile() - Error in regex at offset %d: %s', [ErrorOffset, AnsiString(Error)])); + FCompiled := True +end; + + +constructor TPerlRegEx.Create; +begin + inherited Create; + FState := [preNotEmpty]; + chartable := pcre_maketables; +end; + +destructor TPerlRegEx.Destroy; +begin + CleanUp; + inherited Destroy; +end; + +class function TPerlRegEx.EscapeRegExChars(const S: string): string; +var + I: Integer; +begin + Result := S; + I := Length(Result); + while I > 0 do begin + if Result[I] in ['.', '[', ']', '(', ')', '?', '*', '+', '{', '}', '^', '$', '|', '\'] then + Insert('\', Result, I) + else if Result[I] = #0 then begin + Result[I] := '0'; + Insert('\', Result, I); + end; + Dec(I); + end; +end; + +function TPerlRegEx.GetFoundMatch: Boolean; +begin + Result := OffsetCount > 0; +end; + +function TPerlRegEx.GetMatchedExpression: string; +begin + Assert(FoundMatch, 'REQUIRE: There must be a successful match first'); + Result := GetSubExpressions(0); +end; + +function TPerlRegEx.GetMatchedExpressionLength: Integer; +begin + Assert(FoundMatch, 'REQUIRE: There must be a successful match first'); + Result := GetSubExpressionLengths(0) +end; + +function TPerlRegEx.GetMatchedExpressionOffset: Integer; +begin + Assert(FoundMatch, 'REQUIRE: There must be a successful match first'); + Result := GetSubExpressionOffsets(0) +end; + +function TPerlRegEx.GetSubExpressionCount: Integer; +begin + Assert(FoundMatch, 'REQUIRE: There must be a successful match first'); + Result := OffsetCount-1 +end; + +function TPerlRegEx.GetSubExpressionLengths(Index: Integer): Integer; +begin + Assert(FoundMatch, 'REQUIRE: There must be a successful match first'); + Assert((Index >= 0) and (Index <= SubExpressionCount), 'REQUIRE: Index <= SubExpressionCount'); + Result := Offsets[Index*2+1]-Offsets[Index*2] +end; + +function TPerlRegEx.GetSubExpressionOffsets(Index: Integer): Integer; +begin + Assert(FoundMatch, 'REQUIRE: There must be a successful match first'); + Assert((Index >= 0) and (Index <= SubExpressionCount), 'REQUIRE: Index <= SubExpressionCount'); + Result := Offsets[Index*2] +end; + +function TPerlRegEx.GetSubExpressions(Index: Integer): string; +begin + Assert(FoundMatch, 'REQUIRE: There must be a successful match first'); + if Index > SubExpressionCount then Result := '' + else Result := Copy(FSubject, Offsets[Index*2], Offsets[Index*2+1]-Offsets[Index*2]); +end; + +function TPerlRegEx.Match: Boolean; +var + I, Opts: Integer; +begin + if not Compiled then Compile; + if preNotBOL in State then Opts := PCRE_NOTBOL else Opts := 0; + if preNotEOL in State then Opts := Opts or PCRE_NOTEOL; + if preNotEmpty in State then Opts := Opts or PCRE_NOTEMPTY; + if FStart > FStop then OffsetCount := -1 + else OffsetCount := pcre_exec(Pattern, Hints, FSubjectPChar, FStop, 0, Opts, @Offsets[0], High(Offsets)); + Result := OffsetCount > 0; + // Convert offsets into string indices + if Result then begin + for I := 0 to OffsetCount*2-1 do + Inc(Offsets[I]); + FStart := Offsets[1]; + if Offsets[0] = Offsets[1] then Inc(FStart); // Make sure we don't get stuck at the same position + end; +end; + +function TPerlRegEx.MatchAgain: Boolean; +var + I, Opts: Integer; +begin + if not Compiled then Compile; + if preNotBOL in State then Opts := PCRE_NOTBOL else Opts := 0; + if preNotEOL in State then Opts := Opts or PCRE_NOTEOL; + if preNotEmpty in State then Opts := Opts or PCRE_NOTEMPTY; + if FStart > FStop then OffsetCount := -1 + else OffsetCount := pcre_exec(Pattern, Hints, FSubjectPChar, FStop, FStart-1, Opts, @Offsets[0], High(Offsets)); + Result := OffsetCount > 0; + // Convert offsets into string indices + if Result then begin + for I := 0 to OffsetCount*2-1 do + Inc(Offsets[I]); + FStart := Offsets[1]; + if Offsets[0] = Offsets[1] then Inc(FStart); // Make sure we don't get stuck at the same position + end; +end; + +function TPerlRegEx.NamedSubExpression(const SEName: string): Integer; +begin + Result := pcre_get_stringnumber(Pattern, PChar(SEName)); +end; + +function TPerlRegEx.Config(What: integer):integer; +begin + result:=-1; + pcre_config(what, @result); +end; + + +procedure TPerlRegEx.SetOptions(Value: TPerlRegExOptions); +begin + if (FOptions <> Value) then begin + FOptions := Value; + pcreOptions := 0; + if (preCaseLess in Value) then pcreOptions := pcreOptions or PCRE_CASELESS; + if (preMultiLine in Value) then pcreOptions := pcreOptions or PCRE_MULTILINE; + if (preSingleLine in Value) then pcreOptions := pcreOptions or PCRE_SINGLELINE; + if (preExtended in Value) then pcreOptions := pcreOptions or PCRE_EXTENDED; + if (preAnchored in Value) then pcreOptions := pcreOptions or PCRE_ANCHORED; + if (preDollarEndOnly in Value) then pcreOptions := pcreOptions or PCRE_DOLLAR_ENDONLY; + if (preExtra in Value) then pcreOptions := pcreOptions or PCRE_EXTRA; + if (preUnGreedy in Value) then pcreOptions := pcreOptions or PCRE_UNGREEDY; + if (preUTF8 in Value) then pcreOptions := pcreOptions or PCRE_UTF8; + CleanUp + end +end; + +procedure TPerlRegEx.SetRegEx(const Value: string); +begin + if FRegEx <> Value then begin + FRegEx := Value; + CleanUp + end +end; + +procedure TPerlRegEx.SetStart(const Value: Integer); +begin + if Value < 1 then FStart := 1 + else FStart := Value; + // If FStart > Length(Subject), MatchAgain() will simply return False +end; + +procedure TPerlRegEx.SetStop(const Value: Integer); +begin + if Value > Length(Subject) then FStop := Length(Subject) + else FStop := Value; +end; + +procedure TPerlRegEx.SetSubject(const Value: string); +begin + FSubject := Value; + FSubjectPChar := PChar(Value); + FStart := 1; + FStop := Length(Subject); + OffsetCount := 0; +end; + + + +procedure TPerlRegEx.Study; +var + Error: PChar; +begin + if not FCompiled then Compile; + Hints := pcre_study(Pattern, 0, @Error); + if Error <> nil then raise Exception.Create('TPerlRegEx.Study() - Error studying the regex: ' + AnsiString(Error)); + FStudied := True +end; + + +end. \ No newline at end of file diff --git a/importtxt/doc/changelog_ru.txt b/importtxt/doc/changelog_ru.txt new file mode 100644 index 0000000..9ce2fe5 --- /dev/null +++ b/importtxt/doc/changelog_ru.txt @@ -0,0 +1,77 @@ +v. 0.0.1.9 +* исправлено дублирование сообщения, если оно совпадает с первым в базе +* поддержка исправленного xml_api и поддержка плагина XML Driver (для седьмой ветки) + +v. 0.0.1.8 +* !важный фикс проверки дубликатов ++ добавлена возможность показывать дубликаты ++ автоскролл в окне сообщений ++ добавлена возможность отключить проверку на дубликаты +* баг с кривым выводом статусных сообщений ++ добавлен параметр Codepage в шаблон +- убрана возможность одновременного импорта ++ иконка в окне импорта ++ перечитывание шаблонов, при открытии окна и в Мастере ++ запоминание последнего шаблона ++ полностью переделан импорт из ICQ6 + +v. 0.0.1.7 ++ добавлен шаблон D[i]chat ++ добавлен импорт из ICQ6 ++ добавлен импорт из XML файлов ICQ5 + +v. 0.0.1.6 +* исправлена блокировка папки с импортируемыми файлами ++ добавлен шаблон Pigeon + +v. 0.0.1.5 +* исправлено расширение по умолчанию при выборе папки + +v. 0.0.1.4 ++ добавлена поддержка Updater +* когда не найден заголовок, не загоралась кнопка "завершить" +* исправлен шаблон mContacts + +v. 0.0.1.3 ++ добавлена поддержка бинарных файлов qhf + +v. 0.0.1.2 ++ добавлен параметр DefaultExtension в шаблон ++ добавлена поддержка бинарных файлов, пока только mContact + +v. 0.0.1.1 ++ добавлена возможность автостарта +* обновление списка аккаунтов при его изменении :) + +v. 0.0.1.0 +* пункт меню добавляется всем контактам +* добавлен мастер массового импорта + +v. 0.0.0.6 +* переработан формат файлов шаблона, теперь это ini файлы +* выделен обработчик сообщений перед импортом (удаление переводов строк и пробелов) ++ добавлена поддержка Message Export +* мелкие исправления + +v. 0.0.0.5 +* добавлена поддержка файлов с заголовком, с ником в заголовке сообщениия, но без направления + (History++) + +v. 0.0.0.4 +* добавлена поддержка мультиаккаунтности для 0.8+ +* пункт меню теперь добавляется для всех ICQ протоколов (если несколько копий DLL) + +v. 0.0.0.3 +* изменены процедуры преобразования кодировок +* убраны утечки памяти ++ добавлена собственная иконка + +v. 0.0.0.2 +* изменен способ работы с рег. выражениями (pcre3.dll) ++ сообщения импортируются в базу в UTF8 или ANSI в зависимости от версии Миранды ++ разные кодировки входных файлов ++ фикс перевода + + +v. 0.0.0.1 ++ первый релиз \ No newline at end of file diff --git a/importtxt/doc/examples_ru.txt b/importtxt/doc/examples_ru.txt new file mode 100644 index 0000000..2120fd2 --- /dev/null +++ b/importtxt/doc/examples_ru.txt @@ -0,0 +1,169 @@ + +Пример файла: +************ + + История сообщений с Неизвестный (000000000) + Сохранено из Jimm 07.06.2008 11:49:17 + + +------------------------------------>>>- + Abyss (06.09.2007 17:52:51): +Привет! + +------------------------------------<<<- + Неизвестный (06.09.2007 18:03:09): +Хай + +************ + +Шаблон такой: + +[General] +Name=Jimm import pattern +Charset=ANSI +UseHeader=2 +UsePreMsg=1 +[Message] +Pattern=^------------------------------------(<<<|>>>)-\r\n\s([^\r\n]+?)\s\((\d\d?)\.(\d\d?)\.(\d\d\d?\d?)\s(\d\d?):(\d\d?):(\d\d?)\):$ +In=<<< +Out=>>> +Direction=1 +Day=3 +Month=4 +Year=5 +Hours=6 +Minutes=7 +Seconds=8 +[PreMessage] +PreRN=1 +AfterRN=2 +[Header] +Pattern=^\r\n\tИстория сообщений с ([^\r\n]+?)\s\((\d{5,})\)\r\n\tСохранено из Jimm\s[^\r\n]+?\r\n +InNick=1 +InUID=2 + +Коментарии: основные моменты содержаться в pattern_cfg, +Такие значения RN потому что: +считаем... + +Привет!{\r\n} Раз +{\r\n} два после +------------------------------------<<<- + Неизвестный (06.09.2007 18:03:09):{\r\n} Один до +Хай + +UseHeader=2 используем заголовок только для определения контакта назначения + + +==================================================================================================================================== +Для History++ +============= + +Пример файла +************ + +### +### Полная история +### Abyss (ICQ: 0000000) - Неизвестный (ICQ: 00000000) +### (создана модулем history++) +### + +[06.09.2007 17:52:51] Abyss: +Привет! + +[06.09.2007 18:03:09] Неизвестный: +Хай + +************ +Файл шаблона выглядит так: +************************** +[General] +Name=History++ pattern +Charset=UCS2 +UseHeader=3 +UsePreMsg=1 +[Message] +Pattern=^\[(\d\d?)\.(\d\d?)\.(\d\d\d?\d?)\s(\d\d?):(\d\d?):(\d\d?)\]\s([^\r\n]+?):$ +Direction=7 +Day=1 +Month=2 +Year=3 +Hours=4 +Minutes=5 +Seconds=6 +[Header] +Pattern=^###\r\n###\s[^\r\n]+?\r\n###\s([^\r\n]+?)\s\([^\r\n]+?:\s([^\r\n]+?)\)\s-\s([^\r\n]+?)\s\([^\r\n]+?:\s([^\r\n]+?)\)\r\n###\s[^\r\n]+?\r\n###\r\n +In=3 +Out=1 +InNick=3 +OutNick=1 +InUID=4 +OutUID=2 +[PreMessage] +PreRN=1 +AfterRN=2 +************************** + +Все аналогично только добавляется обработка заголовка, получаем ник для того чтобы потом его использовать в качестве маркера направления + +======================================================================================================================================== + +Для Message Export +================== +Файл: +***** +------------------------------------------------ + History for +User : Неизвестный +Protocol : ICQ +UIN : 00000000 +FirstName : Mister +LastName : X +Age : 0 +Gender : M +e-mail : +Nick : Неизвестный +City : +State : 66 +Phone : +Homepage : +- About - + +------------------------------------------------ +Abyss 06.09.2007 17:52:51 Привет + Как дела? +Неизвестный 06.09.2007 18:03:09 Хай, нормально + +******************* + +[General] +Name=Message export import pattern +Charset=UTF8 +UseHeader=3 +UsePreMsg=1 +[Message] +Pattern=^([^\r\n]+?)[\s]+?(\d\d?)\.(\d\d?)\.(\d\d\d?\d?)\s(\d\d?):(\d\d?):(\d\d?)\s +Direction=1 +Day=2 +Month=3 +Year=4 +Hours=5 +Minutes=6 +Seconds=7 +[Header] +Pattern=^------------------------------------------------\r\n[\s]+?History for\r\nUser[\s]+?:\s([^\r\n]+?)\r\n(.*\r\n)+?Nick[\s]+?:\s([^\r\n]+?)\s\r\n(.*\r\n)+?^------------------------------------------------$ +In=1 +InNick=3 +[PreMessage] +PreRN=0 +AfterRN=1 +PreSP=-2 +********************* + + +Добавлено удаление пробелов в многострочных сообщениях PreSP=-2 + +С этим форматом сообщений бардак: 1) если протокол НЕ ICQ то UID мы не увидим, тоесть ни JID ни что-то там еще не сохраняются + приходится использовать Ник, что не есть гуд + 2) Ник! Зачем писать в файлы пробел после ника???? + Все строчки (Potocol, User, email) нормальные, а после ника пробел. \ No newline at end of file diff --git a/importtxt/doc/importtxt_translate.txt b/importtxt/doc/importtxt_translate.txt new file mode 100644 index 0000000..4220d2e --- /dev/null +++ b/importtxt/doc/importtxt_translate.txt @@ -0,0 +1,105 @@ +;============================================================ +; Module: importtxt.dll +; Plugin: Imports history saved in TXT files from other clients +; Versions: 0.0.0.1 - 0.0.1.2 +; Translators: Abyss +; Dates: 6.09.08 +; Template: +; URL: +;============================================================ +[Imports history saved in TXT files from other clients] +Импортирует историю из текстовых файлов +[Import history to ] +Импортировать историю в +[Import history] +Импорт истории +[Choose a file...] +Выберите файл... +[Choose a pattern...] +Выберите шаблон... +[Choose a file for import...] +Выберите файл для импорта... +[Text files (*.txt)] +Текстовые файлы (*.txt) +[All files (*.*)] +Все файлы (*.*) +[Start] +Старт +;[Close] +[Error in cfg file: ] +Ошибка в cfg файле: +[No Files Patterns Found] +Не найдены файлы шаблонов +[No messages in this file] +В этом файле нет сообщений +[Import started...] +Импорт запущен... +[Added: %d messages] +Добавлено: %d сообщений +[Duplicates: %d messages] +Дубликатов: %d сообщений +[In: %d:%d:%d] +За: %d:%d:%d +[Import not finished. Do you realy want close?] +Импорт не закончен. Вы действительно хотите закрыть? + +[Error adding message to DB] +Ошибка добавления сообщения в Базу + +[Error opening file] +Ошибка открытия файла +[Error mapping file] +Ошибка отображения файла +[Error mapping] +Ошибка отображения + +[Header not found] +Заголовок не найден + +[Import Text Files Wizard] +Мастер Импорта Текстовых Файлов + +[This wizard will help you import message history from some other clients and Miranda plugins, stored in text files.] +Этот мастер поможет вам импортировать сообщения из некоторых других клиентов и плагинов Миранды, хранящуюся в текстовых файлах. +[Click ""Next"" to choose the information you wish to import, or click ""Cancel"" to exit the wizard and continue using Miranda.] +Нажмите "Далее" чтобы выбрать информацию для импортирования, или "Отмена" чтобы выйти из этого мастера. +[It is recommended that you create a backup of your current Miranda profile before importing.] +Рекомендуется создать резервную копию текущего профиля перед импортированием. + +[Choose type of imported files:] +Выберите тип импортируемых файлов: + +[Select files or the whole directory for import:] +Выберите файлы или целую директорию для импорта: +[Files...] +Файлы... +[Path:] +Путь: +[Files:] +Файлы: +[Directory...] +Директория... + +[All previous chosen files will try to import to this protocol.] +Все ранее выбраные файлы будут импортированы в этот протокол. +[Select protocol or account:] +Выберите протокол или аккаунт: +[Click "Next" to start Import or "Cancel" to Abort.] +Нажмите "Далее" для начала Импорта или "Отмена" для выхода. +[Now importing...] +Импортируется... + + +[Select folder for import...] +Выберите папку для импорта... +[File: %s] +Файл: %s +[To: %s] +В: %s +[Can''t determine destination contact] +Не могу определить контакт назначения + +[Default extension] +Расширение по умолчанию +[Its not %s file] +Это не файл %s diff --git a/importtxt/doc/pattern_cfg_ru.txt b/importtxt/doc/pattern_cfg_ru.txt new file mode 100644 index 0000000..e27cf4b --- /dev/null +++ b/importtxt/doc/pattern_cfg_ru.txt @@ -0,0 +1,77 @@ +Структура файла шаблона плагина importtxt начиная с версии 0.0.1.2 +Расширение файла .ini + +[General]* Общие параметры +Name=* Имя шаблона, выводится в списке +Type=* Тип импорта возможные значения + 1 - импорт из текстовых файлов + 2 - импорт из бинарных файлов +*******параметры для импорта текста********* +Charset=* кодировка ANSI, UTF8, UCS2 +Codepage= кодовая страница для ANSI +UseHeader= 0..3 - использовать заголовок + первый бит использовать заголовок для распознавания направления + второй бит использовать заголовок для распознования контакта назначения +UsePreMsg= 0 - не использовать предварительную обработку сообщений, + даже если не используется, то всё равно будут удаляться все переводы строки в конце и в начале + 1 - использовать предварительную обработку +*******параметры для бинарного импорта********* +BinProcedure= Используется для установки процедуры бинарного импорта (обязательна при Type=2) + Возможные значения: + 1 - mContacts + 2 - QHF + 3 - ICQ6 + 4 - ICQ5 +*******общие параметры********* +UseFileName= использовать имя файла для определения UID +DefaultExtension= Расширение файлов по умолчанию (если нет то txt) +*******параметры для импорта текста********* +[Message]* Сообщение +Pattern=* рег. выражение для разбора заголовка сообщения +In= варианты направления, если нет или пустые то используется из заголовка +Out= если UseHeader=0 и In пустой, то ошибка +Direction=* номер подвыражения определяющее направление сообщения (либо жестко заданное либо ник или уин) +Day=* номер подваражения дня +Month=* номер подваражения месяца +Year=* номер подваражения года +Hours=* номер подваражения часов +Minutes=* номер подваражения минут +Seconds= номер подваражения секунд (может быть 0, тогда при импорте принимается за 00) + +[Header] Заголовок файла +Pattern=* рег. выражение заголовка +In=* подвыражение определяющее то что сообщение входящее (Ник, Уин) +Out= подвыражение определяющее то что сообщение исходящее (Ник, Уин) + может быть 0 или отсутствовать, если при импорте Direction<>In тогда оно исходящее, такая случайная фишка, но очень помогающая +InNick=* Ник собеседника +OutNick= Ваш Ник //не используется +InUID=* UID собеседника +OutUID= ваш UID //не используется + +[PreMessage] Обработка сообщения перед импортом в базу +PreRN= удалить переводы строк в начале сообщения (целое число или -1 тогда все) +AfterRN= удалить переводы строк в конце сообщения (целое число или -1 тогда все) +PreSP= удалить пробелы в начале каждой строки сообщения +AfterSP= удалить пробелы в конце каждой строки сообщения + возможные значения: + целое число + -1 все + -2 кол-во равно длине распознаного шаблона заголовка сообщения (актуально для Message Export) + любой параметр может отсутствовать или быть равен нулю, тогда не используется + SP использовать только в случае крайней необходимости, потому что замедляется работа +*******общие параметры********* +[FileName] Имя файла +Pattern=* шаблон для распознования +InNick=* Ник собеседника +OutNick= Ваш Ник //не используется +InUID=* UID собеседника +OutUID= Ваш UID //не используется + + + * обязательная секция, если указаны UseHeader=1, а секции [Header] нет, то ошибка, аналогично с [PreMessage] и [FileName] + * обязательный параметр в секции, если параметр не обязателен то по умолчанию используется либо 0 для PS, либо -1 для RN , либо пустая строка + * если в UseHeader включен второй бит, то обязателен либо InUID, либо InNick, приоритетом распознавания является UID + * в Имени файла аналогично + + UID означает Уникальный ИДентификатор :) это может быть UIN, JID и т.д. + \ No newline at end of file diff --git a/importtxt/doc/readme_ru.txt b/importtxt/doc/readme_ru.txt new file mode 100644 index 0000000..2c7e4c3 --- /dev/null +++ b/importtxt/doc/readme_ru.txt @@ -0,0 +1,78 @@ +Import TXT plugin for Miranda IM +================================ +Плагин предоставляет возможность импортировать историю контактов +из других клиентов, хранящуюся в текстовых файлах. + +Copyright and License +=============================== + +Copyright (C) 2008 Andrey Kunitsyn (Abyss) All Rights Reserved +Some procedures are used written by Alexey Kulakov + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + + +Установка: +========== +1. Сделайте бэкап Базы Миранды +2. Скопируйте importtxt.dll, папку importtxt и всё её содержимое в папку Plugins каталога Миранды. +3. Скопируйте файл pcre3.dll в корень миранды или system32 +4. Содержимое файла importtxt_translate.txt добавьте в конец Лангпака +5. Запустите миранду +В меню контактов появится пункт "Import history..." ("Импортировать историю") +В главном меню появиться такой же пункт - это мастер импорта. + +Для автостарта мастера нужно прописать в базе ImportTXT/AutoStart значение 1 типа byte + +ВАЖНО: +====== +Обязательно сделайте бэкап базы! +Файлы шаблонов должны быть в кодировке ANSI. + + +Описание: +========= +Плагин написан с нацеленностью на универсальность, вы можете написать +свои правила разбора файлов и положить в папку importtxt. +НО есть некоторые ограничения: +1. Входные файлы могут быть в любой кодировке (ANSI, UTF8, UCS2) + (перекодирование происходит с кодовой страницей лангпака, если его нет то с системной) +2. Каждое сообщение в файле должно содержать заголовок с полной информацией о нем: + - направление (входящее или исходящее) + - таймштамп (полная дата, полное время (можно без секунд, но это должно быть обозначено в шаблоне) + - текст сообщения :) +3. Начиная с версии 0.0.0.5 поддерживаются входные файлы следующего вида: + в файле есть заголовок с никами переписывающихся , в заголовке каждого сообщения есть Ник, но нет направления сообщения + (под этот тип подходят файлы экспортируемые History++) +4. Для массового импорта необходима информация о контакте назначения (UID или Ник), в заголовке файла или имени файла. + +Начиная с версии 0.0.1.2 реализована поддержка некоторых бинарных файлов. +(каких именно смотрите pattern_cfg) +Начиная с версии 0.0.1.7 добавлен импорт из XML файлов ICQ5 (для импорта нужно ядро не ниже 0.8.0.21) + +Примерный алгоритм работы: +========================== +В файле ищется регулярное выражение описанное в шаблоне, при помощи подвыражений выделяется дата, время и тд. +Всё что находится после него и до следующего считается текстом сообщения. + +Дубликаты +========= +При импорте происходит простая проверка на дубликаты (направление, таймштамп, размер сообщения) как в import.dll + +Написание шаблона: +================== +Формат файлов шаблона описан в pattern_cfg +Примеры написания с комментариями в examples + +Подробнее о регулярных выражениях вы можете почитать в интернете ;). diff --git a/importtxt/ico/def_ico.ico b/importtxt/ico/def_ico.ico new file mode 100644 index 0000000..eba0fce Binary files /dev/null and b/importtxt/ico/def_ico.ico differ diff --git a/importtxt/importtxt.dpr b/importtxt/importtxt.dpr new file mode 100644 index 0000000..1de1eaa --- /dev/null +++ b/importtxt/importtxt.dpr @@ -0,0 +1,202 @@ +(* + ImportTXT plugin for Miranda IM: the free IM client for Microsoft* Windows* + + Copyright (С) 2008 Abyss + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*) + +{$IMAGEBASE $2080000} +library importtxt; + +uses + m_api, + Windows, + General, + ImportTxtDlg, + ImportTxtWiz; + +{$R imptxt_ver.res} +{$include m_helpers.inc} + + +const + PluginInfo:TPLUGININFOEX=( + cbSize :sizeof(TPLUGININFOEX); + shortName :'Import TXT'; + version :$0000010A; + description:'Imports history saved in TXT files from other clients'; + author :'Abyss'; + authorEmail:'abyss.andrey@gmail.com'; + copyright :'(C)2008 Abyss'; + homepage :'none'; + flags :UNICODE_AWARE; + replacesDefaultModule:0; + uuid:'{6F376B33-D3F4-4c4f-A96B-77DA08043B06}'; + ); + +// Updater compatibility data +const + VersionURL = 'http://abyss.web.ur.ru/itxt_ver.htm'; + VersionPrefix = 'Current version: '; + UpdateURL = 'http://abyss.web.ur.ru/importtxt.zip'; + BetaVersionURL = nil; + BetaVersionPrefix = nil; + BetaUpdateURL = nil; + BetaChangelogURL = nil; + +var + PluginInterfaces:array [0..1] of MUUID; + hwndWizard:HWND; + hwndDialog:HWND; + //Services + SrvITxt,SrvIWiz:Cardinal; + //hooks + onLoadHook:Cardinal; + onAccChangHook:Cardinal; + +function MirandaPluginInfo(mirandaVersion:DWORD):PPLUGININFOEX; cdecl; +begin + MirVers:=mirandaVersion; + result:=@PluginInfo; + //PluginInfo.cbSize:=SizeOf(TPLUGININFO); +end; + +function MirandaPluginInfoEx(mirandaVersion:DWORD):PPLUGININFOEX; cdecl; +begin + MirVers:=mirandaVersion; + result:=@PluginInfo; + //PluginInfo.cbSize:=SizeOf(TPLUGININFOEX); +end; + +function ContactMenuCommand(wParam: WPARAM; lParam: LPARAM): Integer; cdecl; +begin + Result := 0; + if IsWindow(hwndDialog) then + begin + SetForegroundWindow(hwndDialog); + BringWindowToTop(hwndDialog); + end + else + hwndDialog:=CreateDialogParamW(hInstance,MAKEINTRESOURCEW(IDD_IMPDIALOG),0,@IDMainWndProc, wParam); +end; + +function MainMenuCommand(wParam: WPARAM; lParam: LPARAM): Integer; cdecl; +begin + Result:=0; + if (IsWindow(hwndWizard)) then + begin + SetForegroundWindow(hwndWizard); + BringWindowToTop(hwndWizard); + end + else + hwndWizard:=CreateDialogW(hInstance, MAKEINTRESOURCEW(IDD_IMPWIZARD), 0, @WizardDlgProc); +end; + +function OnAccountChanged(wParam:WPARAM;lParam:LPARAM):int;cdecl; +begin + Result:=0; + EnumProtocols; + if Assigned(OnAccountListChange) then OnAccountListChange; +end; + +function OnModulesLoaded(wParam:WPARAM;lParam:LPARAM):int;cdecl; +var upd: TUpdate; + buf:array [0..63] of char; +begin + PluginLink^.UnhookEvent(onloadhook); + Result:=0; + EnumProtocols; + // Register in updater + if Boolean(PluginLink.ServiceExists(MS_UPDATE_REGISTER)) then + begin + ZeroMemory(@upd,SizeOf(upd)); + upd.cpbVersion := SizeOf(upd); + upd.szComponentName := PluginInfo.ShortName;; + upd.pbVersion := CreateVersionStringPlugin(@pluginInfo,buf); + upd.cpbVersion := lstrlen(upd.pbVersion); + upd.szUpdateURL := UpdateURL; + upd.szVersionURL := VersionURL; + upd.pbVersionPrefix := VersionPrefix; + upd.cpbVersionPrefix := Length(VersionPrefix); + upd.szBetaUpdateURL := BetaUpdateURL; + upd.szBetaVersionURL := BetaVersionURL; + upd.pbBetaVersionPrefix := BetaVersionPrefix; + upd.cpbBetaVersionPrefix := length(upd.pbBetaVersionPrefix); + upd.szBetaChangelogURL := BetaChangelogURL; + PluginLink.CallService(MS_UPDATE_REGISTER, 0, DWORD(@upd)); + end; + //check for AutoStart + if (DBReadByte(0,IMPORT_TXT_MODULE,IMPORT_TXT_AS)=1) and + (ProtoCount>0) then + begin + pluginLink^.CallService(IMPORT_WIZ_SERVICE,0,0); + DBWriteByte(0,IMPORT_TXT_MODULE,IMPORT_TXT_AS,0); + end; +end; + + +function Load(link: PPLUGINLINK): int; cdecl; +var + mi: TCListMenuItem; +begin + PLUGINLINK := Pointer(link); + IsMirandaUnicode:=fIsMirandaUnicode; + cp:=pluginLink^.CallService(MS_LANGPACK_GETCODEPAGE, 0, 0); + SrvITxt:=pluginLink^.CreateServiceFunction(IMPORT_TXT_SERVICE, @ContactMenuCommand); + SrvIWiz:=pluginLink^.CreateServiceFunction(IMPORT_WIZ_SERVICE, @MainMenuCommand); + FillChar(mi, sizeof(mi), 0); + mi.cbSize := sizeof(mi); + mi.flags := 0; + mi.position := 1000090050; + mi.hIcon := LoadIcon(hInstance,MAKEINTRESOURCE(IDI_DEFAULT)); + mi.szName.a := 'Import history'; + mi.pszService := IMPORT_TXT_SERVICE; + mi.pszContactOwner:=nil; //All contacts + pluginLink^.CallService(MS_CLIST_ADDCONTACTMENUITEM, 0, int(@mi)); + mi.position := 500050010; + mi.pszService := IMPORT_WIZ_SERVICE; + mi.pszContactOwner:=nil; + pluginLink^.CallService(MS_CLIST_ADDMAINMENUITEM, 0, int(@mi)); + onloadhook:=PluginLink^.HookEvent(ME_SYSTEM_MODULESLOADED,@OnModulesLoaded); + if MirVers>080000 then onAccChangHook:=pluginLink^.HookEvent(ME_PROTO_ACCLISTCHANGED,@OnAccountChanged); + Result := 0; +end; + +function Unload: int; cdecl; +begin + if MirVers>080000 then pluginLink^.UnhookEvent(onAccChangHook); + pluginlink^.DestroyServiceFunction(SrvITxt); + pluginlink^.DestroyServiceFunction(SrvIWiz); + Result := 0; +end; + +function MirandaPluginInterfaces:PMUUID; cdecl; +begin + PluginInterfaces[0]:=PluginInfo.uuid; + PluginInterfaces[1]:=MIID_LAST; + result:=@PluginInterfaces; +end; + + +exports + + Load, Unload, + MirandaPluginInfo, + MirandaPluginInfoEx, + MirandaPluginInterfaces; + +begin +end. diff --git a/importtxt/importtxt/ICQ5_p.ini b/importtxt/importtxt/ICQ5_p.ini new file mode 100644 index 0000000..d2f468a --- /dev/null +++ b/importtxt/importtxt/ICQ5_p.ini @@ -0,0 +1,9 @@ +[General] +Name=ICQ5 xml files import +Type=2 +BinProcedure=4 +DefaultExtension=xml +UseFileName=1 +[FileName] +Pattern=^[^\r\n]+?\\(\d{5,})-(\d{4,})\.xml$ +InUID=1 \ No newline at end of file diff --git a/importtxt/importtxt/ICQ6_p.ini b/importtxt/importtxt/ICQ6_p.ini new file mode 100644 index 0000000..1d99849 --- /dev/null +++ b/importtxt/importtxt/ICQ6_p.ini @@ -0,0 +1,5 @@ +[General] +Name=ICQ6 database +Type=2 +BinProcedure=3 +DefaultExtension=mdb \ No newline at end of file diff --git a/importtxt/importtxt/MAgent_p.ini b/importtxt/importtxt/MAgent_p.ini new file mode 100644 index 0000000..6b54883 --- /dev/null +++ b/importtxt/importtxt/MAgent_p.ini @@ -0,0 +1,23 @@ +[General] +Name=MobileAgent import pattern +Type=1 +Charset=UCS2 +UsePreMsg=1 +UseFileName=1 +[Message] +Pattern=^---------------------------([<>])--\r\n([^\r\n]+?)\s\((\d\d?).(\d\d?).(\d\d\d?\d?)\s(\d\d?).(\d\d?).(\d\d?)\)$ +In=> +Out=< +Direction=1 +Day=3 +Month=4 +Year=5 +Hours=6 +Minutes=7 +Seconds=8 +[PreMessage] +PreRN=1 +AfterRN=2 +[FileName] +Pattern=^[^\r\n]+?\\(\d{5,})\.txt$ +InUID=1 diff --git a/importtxt/importtxt/QHF_p.ini b/importtxt/importtxt/QHF_p.ini new file mode 100644 index 0000000..b6eb687 --- /dev/null +++ b/importtxt/importtxt/QHF_p.ini @@ -0,0 +1,5 @@ +[General] +Name=QHF files import pattern (QIP PDA and Infinum) +Type=2 +BinProcedure=2 +DefaultExtension=qhf \ No newline at end of file diff --git a/importtxt/importtxt/SEmidprms_p.ini b/importtxt/importtxt/SEmidprms_p.ini new file mode 100644 index 0000000..ca0637d --- /dev/null +++ b/importtxt/importtxt/SEmidprms_p.ini @@ -0,0 +1,5 @@ +[General] +Name=Jimm midp-rms SonyEricsson +Type=2 +BinProcedure=5 +DefaultExtension=d \ No newline at end of file diff --git a/importtxt/importtxt/bayanICQ_p.ini b/importtxt/importtxt/bayanICQ_p.ini new file mode 100644 index 0000000..f85bb39 --- /dev/null +++ b/importtxt/importtxt/bayanICQ_p.ini @@ -0,0 +1,9 @@ +[General] +Name=bayanICQ import pattern +Type=2 +BinProcedure=6 +DefaultExtension=hf +UseFileName=1 +[FileName] +Pattern=^[^\r\n]+?\\hist(\d{5,})\.hf$ +InUID=1 \ No newline at end of file diff --git a/importtxt/importtxt/dichat_p.ini b/importtxt/importtxt/dichat_p.ini new file mode 100644 index 0000000..3fd5c6a --- /dev/null +++ b/importtxt/importtxt/dichat_p.ini @@ -0,0 +1,24 @@ +[General] +Name=D[i]Chat import pattern +Type=1 +Charset=ANSI +UseHeader=2 +UsePreMsg=1 +[Message] +Pattern=^---(<<<|>>>)---\r\n\s([^\r\n]+?)\s\((\d\d?)\.(\d\d?)\.(\d\d\d?\d?)\s(\d\d?):(\d\d?):(\d\d?)\):$ +In=<<< +Out=>>> +Direction=1 +Day=3 +Month=4 +Year=5 +Hours=6 +Minutes=7 +Seconds=8 +[PreMessage] +PreRN=1 +AfterRN=2 +[Header] +Pattern=^\tИстория сообщений с ([^\r\n]+?)\s\((\d{5,})\)\r\n\tСохранено из D\[i\]Chat\s[^\r\n]+?\r\n +InNick=1 +InUID=2 \ No newline at end of file diff --git a/importtxt/importtxt/historypp_p.ini b/importtxt/importtxt/historypp_p.ini new file mode 100644 index 0000000..7d5e353 --- /dev/null +++ b/importtxt/importtxt/historypp_p.ini @@ -0,0 +1 @@ +[General] Name=History++ pattern Type=1 Charset=UCS2 UseHeader=3 UsePreMsg=1 [Message] Pattern=^\[(\d\d?)\.(\d\d?)\.(\d\d\d?\d?)\s(\d\d?):(\d\d?):(\d\d?)\]\s([^\r\n]+?):$ Direction=7 Day=1 Month=2 Year=3 Hours=4 Minutes=5 Seconds=6 [Header] Pattern=^###\r\n###\s[^\r\n]+?\r\n###\s([^\r\n]+?)\s\([^\r\n]+?:\s([^\r\n]+?)\)\s-\s([^\r\n]+?)\s\([^\r\n]+?:\s([^\r\n]+?)\)\r\n###\s[^\r\n]+?\r\n###\r\n In=3 Out=1 InNick=3 OutNick=1 InUID=4 OutUID=2 [PreMessage] PreRN=1 AfterRN=2 \ No newline at end of file diff --git a/importtxt/importtxt/jimm_p.ini b/importtxt/importtxt/jimm_p.ini new file mode 100644 index 0000000..10d9ab2 --- /dev/null +++ b/importtxt/importtxt/jimm_p.ini @@ -0,0 +1,24 @@ +[General] +Name=Jimm import pattern +Type=1 +Charset=ANSI +UseHeader=2 +UsePreMsg=1 +[Message] +Pattern=^------------------------------------(<<<|>>>)-\r\n\s([^\r\n]+?)\s\((\d\d?)\.(\d\d?)\.(\d\d\d?\d?)\s(\d\d?):(\d\d?):(\d\d?)\):$ +In=<<< +Out=>>> +Direction=1 +Day=3 +Month=4 +Year=5 +Hours=6 +Minutes=7 +Seconds=8 +[PreMessage] +PreRN=1 +AfterRN=2 +[Header] +Pattern=^\r\n\tИстория сообщений с ([^\r\n]+?)\s\((\d{5,})\)\r\n\tСохранено из Jimm\s[^\r\n]+?\r\n +InNick=1 +InUID=2 diff --git a/importtxt/importtxt/jimmws2_p.ini b/importtxt/importtxt/jimmws2_p.ini new file mode 100644 index 0000000..8f0baa9 --- /dev/null +++ b/importtxt/importtxt/jimmws2_p.ini @@ -0,0 +1,22 @@ +[General] +Name=Jimm import pattern(without seconds) modified +Type=1 +Charset=ANSI +UseHeader=3 +UsePreMsg=1 +[Message] +Pattern=([^\r\n]+?)\s\((\d\d?)\.(\d\d?)\.(\d\d\d?\d?)\s(\d\d?):(\d\d?)\):\r\n +Direction=1 +Day=2 +Month=3 +Year=4 +Hours=5 +Minutes=6 +[PreMessage] +PreRN=1 +AfterRN=2 +[Header] +Pattern=^\r\n\tИстория сообщений с ([^\r\n]+?)\s\((\d{5,})\)\r\n\tСохранено из Jimm\s[^\r\n]+?\r\n +In=1 +InNick=1 +InUID=2 diff --git a/importtxt/importtxt/jimmws_p.ini b/importtxt/importtxt/jimmws_p.ini new file mode 100644 index 0000000..59c609f --- /dev/null +++ b/importtxt/importtxt/jimmws_p.ini @@ -0,0 +1,23 @@ +[General] +Name=Jimm import pattern(without seconds) +Type=1 +Charset=ANSI +UseHeader=2 +UsePreMsg=1 +[Message] +Pattern=^------------------------------------(<<<|>>>)-\r\n\s([^\r\n]+?)\s\((\d\d?)\.(\d\d?)\.(\d\d\d?\d?)\s(\d\d?):(\d\d?)\):$ +In=<<< +Out=>>> +Direction=1 +Day=3 +Month=4 +Year=5 +Hours=6 +Minutes=7 +[PreMessage] +PreRN=1 +AfterRN=2 +[Header] +Pattern=^\r\n\tИстория сообщений с ([^\r\n]+?)\s\((\d{5,})\)\r\n\tСохранено из Jimm\s[^\r\n]+?\r\n +InNick=1 +InUID=2 diff --git a/importtxt/importtxt/mContact_p.ini b/importtxt/importtxt/mContact_p.ini new file mode 100644 index 0000000..925c712 --- /dev/null +++ b/importtxt/importtxt/mContact_p.ini @@ -0,0 +1,9 @@ +[General] +Name=mContact import pattern +Type=2 +BinProcedure=1 +UseFileName=1 +DefaultExtension=dat +[FileName] +Pattern=^[^\r\n]+?\\([^\r\n\\]+?)\.dat$ +InNick=1 \ No newline at end of file diff --git a/importtxt/importtxt/msgexport_p.ini b/importtxt/importtxt/msgexport_p.ini new file mode 100644 index 0000000..933df10 --- /dev/null +++ b/importtxt/importtxt/msgexport_p.ini @@ -0,0 +1,23 @@ +[General] +Name=Message export import pattern +Type=1 +Charset=UTF8 +UseHeader=3 +UsePreMsg=1 +[Message] +Pattern=^([^\r\n]+?)[\s]+?(\d\d?)\.(\d\d?)\.(\d\d\d?\d?)\s(\d\d?):(\d\d?):(\d\d?)\s +Direction=1 +Day=2 +Month=3 +Year=4 +Hours=5 +Minutes=6 +Seconds=7 +[Header] +Pattern=^------------------------------------------------\r\n[\s]+?History for\r\nUser[\s]+?:\s([^\r\n]+?)\r\n(.*\r\n)+?Nick[\s]+?:\s([^\r\n]+?)\s\r\n(.*\r\n)+?^------------------------------------------------$ +In=1 +InNick=3 +[PreMessage] +PreRN=0 +AfterRN=1 +PreSP=-2 \ No newline at end of file diff --git a/importtxt/importtxt/nokmidprms_p.ini b/importtxt/importtxt/nokmidprms_p.ini new file mode 100644 index 0000000..d743b1a --- /dev/null +++ b/importtxt/importtxt/nokmidprms_p.ini @@ -0,0 +1,9 @@ +[General] +Name=Jimm midp-rms Nokia +Type=2 +BinProcedure=5 +DefaultExtension=rms +UseFileName=1 +[FileName] +Pattern=^[^\r\n]+?\\Jimm_m_hist(\d{5,})\.rms$ +InUID=1 \ No newline at end of file diff --git a/importtxt/importtxt/pigeon_p.ini b/importtxt/importtxt/pigeon_p.ini new file mode 100644 index 0000000..7487075 --- /dev/null +++ b/importtxt/importtxt/pigeon_p.ini @@ -0,0 +1,23 @@ +[General] +Name=Pigeon import pattern +Type=1 +Charset=ANSI +UsePreMsg=1 +UseFileName=1 +[Message] +Pattern=^\[(I|O)\s(\d\d?)\.(\d\d?)\.(\d\d\d?\d?)\s(\d\d?):(\d\d?):(\d\d?)\]$ +In=I +Out=O +Direction=1 +Day=2 +Month=3 +Year=4 +Hours=5 +Minutes=6 +Seconds=7 +[PreMessage] +PreRN=1 +AfterRN=2 +[FileName] +Pattern=^[^\r\n]+?\\msg_(\d{5,})\.txt$ +InUID=1 \ No newline at end of file diff --git a/importtxt/importtxt/qip_p.ini b/importtxt/importtxt/qip_p.ini new file mode 100644 index 0000000..ddb112f --- /dev/null +++ b/importtxt/importtxt/qip_p.ini @@ -0,0 +1,23 @@ +[General] +Name=QIP import pattern +Type=1 +Charset=ANSI +UsePreMsg=1 +UseFileName=1 +[Message] +Pattern=^--------------------------------------([<>])-\r\n([^\r\n]+?)\s\((\d\d?):(\d\d?):(\d\d?)\s(\d\d?)/(\d\d?)/(\d\d\d?\d?)\)$ +In=< +Out=> +Direction=1 +Day=6 +Month=7 +Year=8 +Hours=3 +Minutes=4 +Seconds=5 +[PreMessage] +PreRN=1 +AfterRN=2 +[FileName] +Pattern=^[^\r\n]+?\\(\d{5,})\.txt$ +InUID=1 diff --git a/importtxt/importtxt/smaper_p.ini b/importtxt/importtxt/smaper_p.ini new file mode 100644 index 0000000..d02eeda --- /dev/null +++ b/importtxt/importtxt/smaper_p.ini @@ -0,0 +1,23 @@ +[General] +Name=Smaper(vmICQ) import pattern +Type=1 +Charset=UCS2 +UsePreMsg=1 +UseFileName=1 +[Message] +Pattern=^(<-|->)\s\((\d\d?)\.(\d\d?)\.(\d\d\d?\d?)\s(\d\d?)\.(\d\d?)\.(\d\d?)\)$ +In=<- +Out=-> +Direction=1 +Day=2 +Month=3 +Year=4 +Hours=5 +Minutes=6 +Seconds=7 +[PreMessage] +PreRN=1 +AfterRN=2 +[FileName] +Pattern=^[^\r\n]+?\\(\d{5,})\.txt$ +InUID=1 \ No newline at end of file diff --git a/importtxt/importtxt/smapern_p.ini b/importtxt/importtxt/smapern_p.ini new file mode 100644 index 0000000..cce53f0 --- /dev/null +++ b/importtxt/importtxt/smapern_p.ini @@ -0,0 +1,23 @@ +[General] +Name=Smaper (with Nick) import pattern +Type=1 +Charset=UCS2 +UsePreMsg=1 +UseFileName=1 +[Message] +Pattern=^(<-|->)\s[^\r\n]+?\s\((\d\d?)\.(\d\d?)\.(\d\d\d?\d?)\s(\d\d?)\.(\d\d?)\.(\d\d?)\)$ +In=<- +Out=-> +Direction=1 +Day=2 +Month=3 +Year=4 +Hours=5 +Minutes=6 +Seconds=7 +[PreMessage] +PreRN=1 +AfterRN=2 +[FileName] +Pattern=^[^\r\n]+?\\(\d{5,})\.txt$ +InUID=1 \ No newline at end of file diff --git a/importtxt/importtxtdlg.pas b/importtxt/importtxtdlg.pas new file mode 100644 index 0000000..af70699 --- /dev/null +++ b/importtxt/importtxtdlg.pas @@ -0,0 +1,233 @@ +unit ImportTxtDlg; + +interface + +uses + m_api, + Windows, Messages, SysUtils, CommDlg, IniFiles, + ImportThrd, general, ImportTU, FileDlgs; + + +{$I ImpDlgRes.inc} + + +function IDMainWndProc(Dialog:HWnd; hMessage,wParam,lParam:DWord):integer; stdcall; +function GetContactDisplayName(hContact:THandle):string; + +implementation + +{$R ImpTxtDlg.res} + +type TImpTxtDlgData = record + cbSize:integer; + CanStart:boolean; + ChoFile:boolean; + ChoPatt:boolean; + PattFError:boolean; + ITStarted:boolean; + ITFinished:boolean; + StartTime:TDateTime; + FinishTime:TDateTime; + IndexOfPattern:integer; + oFN:integer; + hContact:THandle; + ImportThrd:TImportThrd; + end; + +type PImpTxtDlgData = ^TImpTxtDlgData; + +var ITDD:TImpTxtDlgData; + +function GetContactDisplayName(hContact:THandle):string; +begin + Result := PChar(pluginLink^.CallService(MS_CLIST_GETCONTACTDISPLAYNAME,hContact,0)); +end; + +procedure AddStatusMessage(hDLG:HWND; msg:WideString); +begin + SendDlgItemMessageW(hDLG,IDC_STATUSLIST,LB_SETCURSEL,SendDlgItemMessageW(hDLG,IDC_STATUSLIST,LB_ADDSTRING,0,dword(PWideChar(msg))),0); +end; + +procedure FillComboBox(hDlg:hWnd); //Заполняем список именами шаблонов +var + i:integer; +begin + ITDD.PattFError:=true; + ReadPatterns; + SendDlgItemMessage(hDlg,IDC_TYPECOMBO,CB_RESETCONTENT,0,0); + if PatternsCount>0 then + begin + For i:=0 to PatternsCount-1 do + SendDlgItemMessage(hDlg,IDC_TYPECOMBO,CB_ADDSTRING,0,Integer(PatternNames[i])); + ITDD.PattFError:=false; + end + else + begin + AddStatusMessage(hDlg,TranslateWideString('No Files Patterns Found')); + EnableWindow(GetDlgItem(hDlg, IDC_TYPECOMBO), FALSE); + ITDD.ChoPatt:=false; + end; +end; + +procedure MStart(hDlg:hWnd); //проверяем всё ли сделано чтоб начать импорт +begin +with ITDD do +begin +if ChoFile and ChoPatt and (not PattFError) then + begin + CanStart:=true; + EnableWindow(GetDlgItem(hDlg, IDSTART), TRUE); + end + else + begin + CanStart:=false; + EnableWindow(GetDlgItem(hDlg, IDSTART), FALSE); + end; +end; +end; + + +function IDMainWndProc(Dialog:HWnd; hMessage,wParam,lParam:DWord):integer; stdcall; +//Процедура окна диалога +var + s:WideString; + tempwstr:PWideChar; + +var H,Mi,sec,ms:word; + +begin + result:=0; + case hMessage of + WM_DESTROY: begin + if ITDD.ImportThrd<>Nil then ITDD.ImportThrd.Terminate; + SetLastPattern(SendDlgItemMessage(Dialog, IDC_TYPECOMBO, CB_GETCURSEL, 0, 0)); + end; + WM_INITDIALOG: begin + TranslateDialogDefault(Dialog); + tempwstr:=ANSIToWide(PChar(GetContactDisplayName(lParam)),tempwstr,cp); + s:=TranslateWideString(WideFormat('Import history to %s (%s)',[tempwstr,GetContactID(lParam)])); + SetWindowTextW(Dialog,PWideChar(s)); + SendMessage(Dialog,WM_SETICON,ICON_SMALL,LoadIcon(hInstance,MAKEINTRESOURCE(IDI_DEFAULT))); + FillChar(ITDD,SizeOf(TImpTxtDlgData),0); + with ITDD do begin + cbSize:=SizeOf(TImpTxtDlgData); + hContact:=lParam; + CanStart:=false; + ChoFile:=false; + ChoPatt:=true; + PattFError:=false; + ITStarted:=false; + ITFinished:=false; + end; + + FillComboBox(Dialog); + SendDlgItemMessage(Dialog, IDC_TYPECOMBO, CB_SETCURSEL, GetLastPattern, 0); + ITDD.IndexOfPattern:=GetLastPattern; + MStart(Dialog); + CheckDlgButton(Dialog,IDC_CHKDUP,BST_CHECKED); + CheckForDuplicates:=true; + CheckDlgButton(Dialog,IDC_SHOWDUP,BST_UNCHECKED); + CheckForDuplicates:=false; + ShowWindow(Dialog,SW_NORMAL); + end; + WM_COMMAND: begin + if (HiWord(wParam)=CBN_SELCHANGE) and (LoWord(wParam)=IDC_TYPECOMBO) then //Сделали выбор шаблона + begin + ITDD.ChoPatt:=true; + ITDD.IndexOfPattern:=SendDlgItemMessage(Dialog, IDC_TYPECOMBO, CB_GETCURSEL, 0, 0); + MStart(Dialog); + end; + if (HiWord(wParam)=BN_CLICKED) and (LoWord(wParam)=IDC_CHKDUP) then + if LongBool(IsDlgButtonChecked(Dialog,IDC_CHKDUP)) then EnableWindow(GetDlgItem(Dialog, IDC_SHOWDUP), TRUE) + else EnableWindow(GetDlgItem(Dialog, IDC_SHOWDUP), FALSE); + case loword(wParam) of + IDCLOSE: DestroyWindow(Dialog); + IDC_BRWSBTN: begin //Нажали кнопку "..." + s:=OpenDialogExecute(Dialog,0,ITDD.oFN,TxtPatterns[ITDD.IndexOfPattern].DefExtension); + if s<>'' then ITDD.ChoFile:=true + else ITDD.ChoFile:=false; + SendDlgItemMessageW(Dialog, IDC_FILENAME,WM_SETTEXT,0,dword(PWideChar(s))); + MStart(Dialog); + end; + IDSTART: begin //Старт + with ITDD do + if CanStart then + begin + EnableWindow(GetDlgItem(Dialog, IDSTART), FALSE); + EnableWindow(GetDlgItem(Dialog, IDCLOSE), FALSE); + EnableWindow(GetDlgItem(Dialog, IDC_TYPECOMBO), FALSE); + EnableWindow(GetDlgItem(Dialog, IDC_BRWSBTN), FALSE); + ImportThrd:=TImportThrd.Create(TRUE); + ImportThrd.FreeOnTerminate:=true; + ImportThrd.DContact.hContact:=hContact; + CheckForDuplicates:=LongBool(IsDlgButtonChecked(Dialog,IDC_CHKDUP)); + ShowDuplicates:=LongBool(IsDlgButtonChecked(Dialog,IDC_SHOWDUP)); + h:=SendDlgItemMessageW(Dialog, IDC_FILENAME,WM_GETTEXTLENGTH,0,0)+1; + SetLength(s,h); + SendDlgItemMessageW(Dialog, IDC_FILENAME,WM_GETTEXT,h,dword(PWideChar(s))); + ImportThrd.FileNames:=s+#0+#0; + ImportThrd.OffsetFileName:=oFN; + ImportThrd.WorkPattern:=TxtPatterns[IndexOfPattern]; + ImportThrd.ParentHWND:=Dialog; + ImportThrd.Resume; + end; + end; + end; + end; + WM_CLOSE: begin + DestroyWindow(Dialog); + end; + //Далее оброботка сообщений от потока импорта + //Начали + ITXT_THREAD_ALLSTARTED:begin + ITDD.ITStarted:=true; + ITDD.StartTime:=Time; + end; + ITXT_THREAD_START:begin + AddStatusMessage(Dialog,TranslateWideString('Import started...')); + end; + //Известна длинна файла выставляем диапазон прогрессбара + ITXT_THREAD_MAXPROGRESS: + SendDlgItemMessage(Dialog,IDC_PROGRESS,PBM_SETRANGE,0,MakeLParam(0,lParam)); + //Идет прогресс ... + ITXT_THREAD_PROGRESS: + SendDlgItemMessage(Dialog,IDC_PROGRESS,PBM_SETPOS,wParam,0); + //Возникла ошибка + ITXT_THREAD_ERROR: + AddStatusMessage(Dialog,TranslateWideString(PWideChar(wParam))); + //Закончили + ITXT_THREAD_FINISH:begin + ITDD.ITFinished:=true; + ITDD.FinishTime:=Time; + DecodeTime(ITDD.FinishTime-ITDD.StartTime,h,mi,sec,ms); + AddStatusMessage(Dialog,WideFormat(TranslateWideString('Added: %d messages'),[wParam])); + AddStatusMessage(Dialog,WideFormat(TranslateWideString('Duplicates: %d messages'),[lParam])); + AddStatusMessage(Dialog,WideFormat(TranslateWideString('In: %d:%d:%d'),[h,mi,sec])); + AddStatusMessage(Dialog,''); + SendDlgItemMessageW(Dialog, IDC_FILENAME,WM_SETTEXT,0,0); + ITDD.ChoFile:=false; + EnableWindow(GetDlgItem(Dialog, IDC_TYPECOMBO), TRUE); + EnableWindow(GetDlgItem(Dialog, IDC_BRWSBTN), TRUE); + EnableWindow(GetDlgItem(Dialog, IDCLOSE), TRUE); + end; + //начали новый файл + ITXT_THREAD_START_FILE: + AddStatusMessage(Dialog,WideFormat(TranslateWideString('File: %s'),[PWideChar(wParam)])); + //определили контакт + ITXT_THREAD_DEST_CONTACT:begin + if IsMirandaUnicode then + begin + tempwstr:=UTF8toWide(PChar(GetContactID(wParam,'',true)),tempwstr); + s:= tempwstr; + tempwstr:=UTF8toWide(PChar(GetContactNick(wParam,'',true)),tempwstr); + s:=s + ' | ' + tempwstr; + end + else + s:=GetContactID(wParam,'',true)+' | '+GetContactNick(wParam,'',true); + + AddStatusMessage(Dialog,WideFormat(TranslateWideString('To: %s'),[s])); + end; + end; +end; + +end. \ No newline at end of file diff --git a/importtxt/make.bat b/importtxt/make.bat new file mode 100644 index 0000000..fc878f2 --- /dev/null +++ b/importtxt/make.bat @@ -0,0 +1,10 @@ +set COMPDIR=-$A8 -$D- -$J+ -$L- -$O+ -$Q- -$R- -$Y- -$C- +set INCDIR="c:\program files\borland\delphi7\lib\kol;..\..\include;" +set OUTDIR="..\plugins" +set DCUDIR="tmp" +md %DCUDIR% 2>nul +brcc32 -foImpTxt_Ver.res ImpTxt_Ver.rc +brcc32 -foImpTxtDlg.res ImpTxtDlg.rc +brcc32 -foImpTxtWiz.res ImpTxtWiz.rc +dcc32 -B -CG -U%INCDIR% -R%INCDIR% -I%INCDIR% -E%OUTDIR% -LE%DCUDIR% -LN%DCUDIR% -N%DCUDIR% %COMPDIR% importtxt.dpr +rd /q /s %DCUDIR% \ No newline at end of file -- cgit v1.2.3