TextMessageService.pas 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498
  1. unit TextMessageService;
  2. interface
  3. uses
  4. BaseService, PerlRegEx, Classes, SysUtils, StrUtils, RealICQModel, Forms;
  5. type
  6. TTextMessageService = class(TBaseService)
  7. private
  8. FMessages, FTeamMessages: TStringList;
  9. function GetImageReplacementStr(AImgUrl: string; ATalkingForm: TForm): string;
  10. function GetMapReplacementStr(AImgUrl: string; ATalkingForm: TForm): string;
  11. function GetVoiceReplacementStr(AVoiceUrl: string): string;
  12. function GetGradeReplacementStr(AGradeUrl: string; AShowForm: Boolean = False): string;
  13. procedure OnUploaded(ASender: TObject);
  14. procedure UploadFaces(AMsg: TObject; AFaces: TStringList);
  15. public
  16. procedure HandleAsycTextMessage(AData: array of Byte);
  17. procedure SendMessage(AMsg: TRealICQMessage; AFaces: TStringList); overload;
  18. procedure SendMessage(AMsg: TRealICQTeamMessage; AFaces: TStringList); overload;
  19. function CreateMessage: TRealICQMessage;
  20. function CreateTeamMessage: TRealICQTeamMessage;
  21. function GetMessage(AMessageID: string): TRealICQMessage;
  22. function GetTeamMessage(AMessageID: string): TRealICQTeamMessage;
  23. function PreProccess(ATalkingForm: TForm; ASender: string; AMessageContent: string; AShowCustomFace: Boolean = True): string;
  24. function ContentFilter(AMsg: TRealICQMessage): string;
  25. procedure Init;
  26. procedure Uninstall;
  27. constructor Create;
  28. destructor Destroy; override;
  29. class function GetService: TTextMessageService; static;
  30. end;
  31. implementation
  32. uses
  33. Windows, RealICQDBHistory, MainFrm, TalkingFrm, IdURI, ShareUtils,
  34. DownloadFaceWithHttp, RealICQClient, MessagesHander, HttpDownloader, MD5,
  35. BaseChromeView, UsersService, RealICQUtility;
  36. var
  37. ATextMessageService: TTextMessageService;
  38. const
  39. IMAGE_LOADED_TAG: string = '<img oncontextmenu="location.href=''FaceMenu_%s'';return false;" src="%s" align="absBottom" hspace="1" onload="AutoResizeImage(250,250,this)" onclick="openInIE(this)">';
  40. IMAGE_LOADING_TAG: string = '<img ID = "%s" oncontextmenu="location.href=''FaceMenu_%s'';return false;" src="%s" align="absBottom" hspace="1" onload="AutoResizeImage(250,250,this)" onclick="openInIE(this)">';
  41. VOICE_TAG: string = '<object id="%s" width="300" height="63" classid="CLSID:6BF52A52-394A-11d3-B153-00C04F79FAA6" codebase="http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=7.0" align="top" border="0" type="application/x-oleobject">' + '<param name="URL" value="%s">' + '<param name="AUTOSTART" value="0">' + '<param name="uiMode" value="mini">' + '</object>';
  42. MAP_IFRAME_TAG: string = '<iframe src="%s" frameborder="no" border="0" ></iframe>';
  43. { TTextMessageService }
  44. function TTextMessageService.ContentFilter(AMsg: TRealICQMessage): string;
  45. var
  46. reg: TPerlRegEx;
  47. begin
  48. reg := TPerlRegEx.Create;
  49. try
  50. reg.Subject := AMsg.MessageStr;
  51. reg.RegEx := '\[(\w+)\-src=\"(http://[\w\W]+)\"]';
  52. while reg.MatchAgain do
  53. begin
  54. if CompareText(reg.Groups[1], 'grade') = 0 then
  55. begin
  56. reg.Replacement := GetGradeReplacementStr(reg.Groups[2], not SameText(TUsersService.GetUsersService.GetMe.LoginName, AMsg.Sender));
  57. reg.Subject := reg.Replace();
  58. end;
  59. end;
  60. Result := reg.Subject;
  61. finally
  62. reg.Free;
  63. end;
  64. end;
  65. constructor TTextMessageService.Create;
  66. begin
  67. FMessages := TStringList.Create;
  68. FTeamMessages := TStringList.Create;
  69. inherited;
  70. end;
  71. function TTextMessageService.CreateMessage: TRealICQMessage;
  72. begin
  73. Result := TRealICQMessage.Create(MainForm.RealICQClient.LoginName, '', '', '', False);
  74. with Result do
  75. begin
  76. MessageID := GetTickCount;
  77. while FMessages.IndexOf(IntToStr(MessageID)) >= 0 do
  78. begin
  79. Sleep(100);
  80. MessageID := GetTickCount;
  81. end;
  82. SendDateTime := Now;
  83. FMessages.InsertObject(0, IntToStr(MessageID), Result);
  84. end;
  85. end;
  86. function TTextMessageService.CreateTeamMessage: TRealICQTeamMessage;
  87. begin
  88. Result := TRealICQTeamMessage.Create('', '', '', '', False);
  89. with Result do
  90. begin
  91. MessageID := GetTickCount;
  92. while FTeamMessages.IndexOf(IntToStr(MessageID)) >= 0 do
  93. begin
  94. Sleep(100);
  95. MessageID := GetTickCount;
  96. end;
  97. SendDateTime := Now;
  98. FTeamMessages.InsertObject(0, IntToStr(MessageID), Result);
  99. end;
  100. end;
  101. destructor TTextMessageService.Destroy;
  102. begin
  103. TRealICQUtility.FreeStringList(FMessages);
  104. TRealICQUtility.FreeStringList(FTeamMessages);
  105. inherited;
  106. end;
  107. class function TTextMessageService.GetService: TTextMessageService;
  108. begin
  109. if ATextMessageService = nil then
  110. ATextMessageService := TTextMessageService.Create;
  111. Result := ATextMessageService;
  112. end;
  113. function TTextMessageService.GetTeamMessage(AMessageID: string): TRealICQTeamMessage;
  114. var
  115. i: Integer;
  116. begin
  117. i := FMessages.IndexOf(AMessageID);
  118. if i > -1 then
  119. Result := FMessages.Objects[i] as TRealICQTeamMessage;
  120. end;
  121. function TTextMessageService.GetGradeReplacementStr(AGradeUrl: string; AShowForm: Boolean = False): string;
  122. var
  123. AForm: TBaseChromeViewForm;
  124. begin
  125. Result := '请您为我们这次服务给个评分或提个建议,谢谢!';
  126. if AShowForm then
  127. begin
  128. AForm := TBaseChromeViewForm.Create(nil);
  129. try
  130. AForm.Caption := '评分系统';
  131. AForm.ChangeUIColor(MainForm.FormColor);
  132. AForm.Width := 720;
  133. AForm.Height := 394;
  134. AForm.Top := (Screen.Height - 394) div 2;
  135. AForm.Left := (Screen.Width - 720) div 2;
  136. AForm.URL := AnsiReplaceText(AGradeUrl, '&amp;', '&');
  137. AForm.Show;
  138. finally
  139. end;
  140. end;
  141. end;
  142. function TTextMessageService.GetVoiceReplacementStr(AVoiceUrl: string): string;
  143. var
  144. AMD5String, ALocalPath, AFileName, AFaceID: string;
  145. AURL: TIdURI;
  146. ATask: THttpDownloader;
  147. WaitingFace: TWaitingFace;
  148. begin
  149. // Result := Format(MAP_IFRAME_TAG, [ExtractFilePath(Application.ExeName) + 'html\mp3.html']);
  150. AURL := TIdURI.Create();
  151. AURL.URI := AVoiceUrl;
  152. AMD5String := ChangeFileExt(ExtractFileName(AURL.Document), '');
  153. if not (CompareText(ExtractFileExt(AURL.Document), '.mp3') = 0) then
  154. begin
  155. Result := '对不起,目前只支持MP3音频格式';
  156. AURL.Free;
  157. Exit;
  158. end;
  159. ALocalPath := TRealICQClient.GetReceivedFaceDir + ExtractFileName(AURL.Document);
  160. AFileName := ReplaceStr(ALocalPath, '\', '/');
  161. // Dialog.ShowMessage(Format(VOICE_TAG, ['voice_'+AMD5String, AFileName]));
  162. Result := Format(VOICE_TAG, ['voice_' + AMD5String, AFileName]);
  163. if not FileExists(ALocalPath) then
  164. begin
  165. ATask := THttpDownloader.Create(AURL.URI, ALocalPath, AThreadPool.AcquireYarn);
  166. AThreadPool.StartYarn(ATask.Yarn, ATask);
  167. end;
  168. AURL.Free;
  169. end;
  170. procedure TTextMessageService.HandleAsycTextMessage(AData: array of Byte);
  171. var
  172. FontStrLength, SenderLoginNameLength, ReceiverLoginNameLength: Byte;
  173. nIndex, IsEncry, MessageStrLength: SmallInt;
  174. MessageID: Cardinal;
  175. SendDateTime: TDateTime;
  176. SenderLoginName, ReceiverLoginName, FontStr, MessageStr: string;
  177. RealICQMessage: TRealICQMessage;
  178. RealICQUser: TRealICQUser;
  179. TalkingForm: TTalkingForm;
  180. begin
  181. nIndex := 0;
  182. //取 (3)接收人用户名长度 1byte
  183. CopyMemory(@ReceiverLoginNameLength, @AData[nIndex], 1);
  184. Inc(nIndex, 1);
  185. //取 (4)接收人用户名 动态长度,由(3)指定,接收消息的用户的用户名,如果是服务器中转此处会变成消息的发送人。
  186. SetLength(ReceiverLoginName, ReceiverLoginNameLength);
  187. CopyMemory(PChar(ReceiverLoginName), @AData[nIndex], ReceiverLoginNameLength);
  188. Inc(nIndex, ReceiverLoginNameLength);
  189. //取 (5)发送人用户名长度 1byte
  190. CopyMemory(@SenderLoginNameLength, @AData[nIndex], 1);
  191. Inc(nIndex, 1);
  192. //取 (6)发送人用户名 动态长度,由(5)指定。
  193. SetLength(SenderLoginName, SenderLoginNameLength);
  194. CopyMemory(PChar(SenderLoginName), @AData[nIndex], SenderLoginNameLength);
  195. Inc(nIndex, SenderLoginNameLength);
  196. //取 (7)消息的编号 4byte,无符号32位整型数据
  197. CopyMemory(@MessageID, @AData[nIndex], 4);
  198. Inc(nIndex, 4);
  199. //取 (8)发送消息的时间 8byte,64位浮点类型(double即TDateTime类型)
  200. CopyMemory(@SendDateTime, @AData[nIndex], 8);
  201. Inc(nIndex, 8);
  202. //取 (9)字体信息长度 1byte,
  203. CopyMemory(@FontStrLength, @AData[nIndex], 1);
  204. Inc(nIndex, 1);
  205. //取 (10)字体信息 动态长度,由(9)指定。
  206. SetLength(FontStr, FontStrLength);
  207. CopyMemory(PChar(FontStr), @AData[nIndex], FontStrLength);
  208. Inc(nIndex, FontStrLength);
  209. //取 (11)消息的长度 2byte,无符号16位整型。
  210. CopyMemory(@MessageStrLength, @AData[nIndex], 2);
  211. Inc(nIndex, 2);
  212. //取 (12)消息内容 动态长度,由(11)指定。
  213. SetLength(MessageStr, MessageStrLength);
  214. CopyMemory(PChar(MessageStr), @AData[nIndex], MessageStrLength);
  215. Inc(nIndex, MessageStrLength);
  216. //取(11)是否是私密消息
  217. CopyMemory(@IsEncry, @AData[nIndex], 1);
  218. RealICQMessage := TRealICQMessage.Create(SenderLoginName, ReceiverLoginName, FontStr, MessageStr, IsEncry = 1);
  219. RealICQMessage.MessageID := GetTickCount; //设为接收到此消息的时间,以便及时删除无用的消息
  220. RealICQMessage.SendDateTime := SendDateTime;
  221. MainForm.DBHistory.SaveMessage('-1', RealICQMessage.Sender, RealICQMessage.Receiver, RealICQMessage.SendDateTime, RealICQMessage.FontStr, RealICQMessage.MessageStr, RealICQMessage.IsEncryMessage);
  222. TalkingForm := GetTalkingForm(ReceiverLoginName, MainForm.RealICQClient);
  223. if (TalkingForm <> nil) and (TalkingForm.CanWriteMessage) then
  224. begin
  225. TalkingForm.ShowMessage(RealICQMessage, false);
  226. end;
  227. end;
  228. procedure TTextMessageService.Init;
  229. begin
  230. TRealICQUtility.ClearStringList(FMessages);
  231. TRealICQUtility.ClearStringList(FTeamMessages);
  232. end;
  233. function TTextMessageService.PreProccess(ATalkingForm: TForm; ASender: string; AMessageContent: string; AShowCustomFace: Boolean = True): string;
  234. var
  235. Face: TFace;
  236. iLoop, iStart, iIndex: Integer;
  237. MD5String: string;
  238. WaitingFace: TWaitingFace;
  239. FaceID, AFileName, ContextMenuStr: string;
  240. reg: TPerlRegEx;
  241. procedure ReplacesTag;
  242. begin
  243. while reg.MatchAgain do
  244. begin
  245. MD5String := reg.Groups[1];
  246. iIndex := MainForm.FaceList.IndexOf(MD5String);
  247. if not AShowCustomFace then
  248. begin
  249. AFileName := ReplaceStr(FindRecvedFace(MD5String), '\', '/');
  250. FaceID := MD5String + IntToStr(GetTickCount) + IntToStr(WaitingFaces.Count) + IntToStr(iStart);
  251. reg.Replacement := Format(IMAGE_LOADING_TAG, [FaceID, MD5String, AFileName]);
  252. reg.Subject := ReplaceStr(reg.Subject, reg.Groups[0], reg.Replacement);
  253. end
  254. else if iIndex >= 0 then
  255. begin
  256. Face := MainForm.FaceList.Objects[iIndex] as TFace;
  257. reg.Replacement := Format(IMAGE_LOADED_TAG, [MD5String, Face.FileName]);
  258. reg.Subject := ReplaceStr(reg.Subject, reg.Groups[0], reg.Replacement);
  259. end
  260. else if FileExists(FindRecvedFace(MD5String)) then
  261. begin
  262. AFileName := ReplaceStr(FindRecvedFace(MD5String), '\', '/');
  263. reg.Replacement := Format(IMAGE_LOADED_TAG, [MD5String, AFileName]);
  264. reg.Subject := ReplaceStr(reg.Subject, reg.Groups[0], reg.Replacement);
  265. end
  266. else
  267. begin
  268. if ATalkingForm <> nil then
  269. with (ATalkingForm as TTalkingForm) do
  270. begin
  271. AFileName := ExtractFilePath(Application.ExeName) + 'Images\progress.gif';
  272. AFileName := ReplaceStr(AFileName, '\', '/');
  273. FaceID := MD5String + IntToStr(GetTickCount) + IntToStr(WaitingFaces.Count) + IntToStr(iStart);
  274. reg.Replacement := Format(IMAGE_LOADING_TAG, [FaceID, MD5String, AFileName]);
  275. reg.Subject := ReplaceStr(reg.Subject, reg.Groups[0], reg.Replacement);
  276. if WaitingFaces.IndexOf(MD5String) <> -1 then
  277. Continue;
  278. if Category = tcNormal then
  279. FRealICQClient.PleaseSendFaceToMe(Receiver, MD5String)
  280. else
  281. FRealICQClient.DownloadTeamFace(ASender, MD5String);
  282. if AShowCustomFace then
  283. begin
  284. WaitingFace := TWaitingFace.Create;
  285. WaitingFace.FFaceMD5Code := MD5String;
  286. WaitingFace.FWebBrowser := WebBrowser;
  287. WaitingFace.FFaceID := FaceID;
  288. WaitingFaces.AddObject(MD5String, WaitingFace);
  289. end;
  290. end
  291. else
  292. begin
  293. AFileName := ExtractFilePath(Application.ExeName) + 'Images\erre.gif';
  294. AFileName := ReplaceStr(AFileName, '\', '/');
  295. FaceID := MD5String + IntToStr(GetTickCount);
  296. reg.Replacement := Format(IMAGE_LOADING_TAG, [FaceID, MD5String, AFileName]);
  297. reg.Subject := ReplaceStr(reg.Subject, reg.Groups[0], reg.Replacement);
  298. end;
  299. end;
  300. end;
  301. end;
  302. begin
  303. reg := TPerlRegEx.Create;
  304. try
  305. reg.Subject := AMessageContent;
  306. reg.RegEx := '\[(\w+)\-src=\"(http://[\w\W]+?)\"\]';
  307. while reg.MatchAgain do
  308. begin
  309. if CompareText(reg.Groups[1], 'IMAGE') = 0 then
  310. begin
  311. reg.Replacement := GetImageReplacementStr(reg.Groups[2], ATalkingForm);
  312. reg.Subject := reg.Replace();
  313. end
  314. else if CompareText(reg.Groups[1], 'MAP') = 0 then
  315. begin
  316. reg.Replacement := GetMapReplacementStr(reg.Groups[2], ATalkingForm);
  317. reg.Subject := reg.Replace();
  318. end
  319. else if CompareText(reg.Groups[1], 'voice') = 0 then
  320. begin
  321. reg.Replacement := GetVoiceReplacementStr(reg.Groups[2]);
  322. reg.Subject := reg.Replace();
  323. end;
  324. end;
  325. AMessageContent := reg.Subject;
  326. finally
  327. reg.Free;
  328. end;
  329. reg := TPerlRegEx.Create;
  330. try
  331. reg.Subject := AMessageContent;
  332. reg.RegEx := '\[IMG:([\w\W]+?)\]';
  333. ReplacesTag;
  334. reg.RegEx := '\[image\-src=\"([\w\W]+?)\"\]';
  335. ReplacesTag;
  336. AMessageContent := reg.Subject;
  337. finally
  338. reg.Free;
  339. end;
  340. //取系统表情
  341. for iLoop := 0 to MainForm.SystemFaceCount - 1 do
  342. begin
  343. Face := MainForm.FaceList.Objects[iLoop] as TFace;
  344. ContextMenuStr := 'oncontextmenu="location.href=''StandardFaceMenu_' + Face.ShortCut + ''';return false;"';
  345. AMessageContent := AnsiReplaceStr(AMessageContent, Face.ShortCut, '<img ' + ContextMenuStr + ' src="' + Face.FileName + '" align="absBottom" hspace="1" >');
  346. end;
  347. Result := AMessageContent;
  348. end;
  349. procedure TTextMessageService.OnUploaded(ASender: TObject);
  350. begin
  351. end;
  352. procedure TTextMessageService.UploadFaces(AMsg: TObject; AFaces: TStringList);
  353. begin
  354. end;
  355. procedure TTextMessageService.SendMessage(AMsg: TRealICQTeamMessage; AFaces: TStringList);
  356. begin
  357. if Assigned(AFaces) and (AFaces.Count > 0) then
  358. UploadFaces(AMsg, AFaces)
  359. else
  360. end;
  361. procedure TTextMessageService.Uninstall;
  362. begin
  363. end;
  364. procedure TTextMessageService.SendMessage(AMsg: TRealICQMessage; AFaces: TStringList);
  365. begin
  366. end;
  367. function TTextMessageService.GetImageReplacementStr(AImgUrl: string; ATalkingForm: TForm): string;
  368. var
  369. AMD5String, ALocalPath, AFileName, AFaceID: string;
  370. AURL: TIdURI;
  371. ATask: TDownloadFaceTask;
  372. WaitingFace: TWaitingFace;
  373. begin
  374. AURL := TIdURI.Create();
  375. AURL.URI := AImgUrl;
  376. AMD5String := ChangeFileExt(ExtractFileName(AURL.Document), '');
  377. ALocalPath := TRealICQClient.GetReceivedFaceDir + AMD5String + ExtractFileExt(AURL.Params);
  378. if FileExists(ALocalPath) then
  379. begin
  380. AFileName := ReplaceStr(ALocalPath, '\', '/');
  381. Result := Format(IMAGE_LOADED_TAG, [AMD5String, AFileName]);
  382. end
  383. else
  384. begin
  385. if ATalkingForm <> nil then
  386. begin
  387. AFaceID := AMD5String + IntToStr(GetTickCount) + IntToStr(WaitingFaces.Count);
  388. AFileName := ExtractFilePath(Application.ExeName) + 'Images\progress.gif';
  389. Result := Format(IMAGE_LOADING_TAG, [AFaceID, AMD5String, AFileName]);
  390. WaitingFace := TWaitingFace.Create;
  391. WaitingFace.FFaceMD5Code := AMD5String;
  392. WaitingFace.FWebBrowser := (ATalkingForm as TTalkingForm).WebBrowser;
  393. WaitingFace.FFaceID := AFaceID;
  394. WaitingFaces.AddObject(AMD5String, WaitingFace);
  395. ATask := TDownloadFaceTask.Create(AURL.URI, ALocalPath, AThreadPool.AcquireYarn);
  396. AThreadPool.StartYarn(ATask.Yarn, ATask);
  397. end
  398. else
  399. begin
  400. AFaceID := AMD5String + IntToStr(GetTickCount);
  401. AFileName := ExtractFilePath(Application.ExeName) + 'Images\error.gif';
  402. Result := Format(IMAGE_LOADING_TAG, [AFaceID, AMD5String, AFileName]);
  403. end;
  404. end;
  405. AURL.Free;
  406. end;
  407. function TTextMessageService.GetMapReplacementStr(AImgUrl: string; ATalkingForm: TForm): string;
  408. begin
  409. Result := Format(MAP_IFRAME_TAG, [AnsiReplaceText(AImgUrl, '&amp;', '&')]);
  410. end;
  411. function TTextMessageService.GetMessage(AMessageID: string): TRealICQMessage;
  412. var
  413. i: Integer;
  414. begin
  415. i := FMessages.IndexOf(AMessageID);
  416. if i > -1 then
  417. Result := FMessages.Objects[i] as TRealICQMessage;
  418. end;
  419. end.