OSDN Git Service

パネルの配置についてコメント追加
[winbottle/winbottle.git] / bottleclient / MainForm.pas
1 unit MainForm;
2
3 {
4 \83A\83v\83\8a\83P\81[\83V\83\87\83\93\82Ì\83\81\83C\83\93\83t\83H\81[\83\80\81B
5 \91\97\90M\81E\8eó\90M\81E\83{\83g\83\8b\94z\91\97\8aÖ\8cW\82Ì\82¢\82ë\82¢\82ë\82È\8f\88\97\9d\82ð\8ds\82¤\81B
6 }
7
8 interface
9
10 uses
11   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
12   Menus, StdCtrls, ComCtrls, BRegExp, BottleDef, BottleSstp,
13   DirectSstp, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient,
14   IdSLPP20, SsParser, ImgList, AppEvnts, TaskTray, StdActns,
15   ActnList, MPlayer, MenuBar, ToolWin,
16   IniFiles, ExtCtrls, ShellAPI, Contnrs,
17   ConstEditor, Buttons, Clipbrd, HeadValue, Logs, MultipleChoiceEditor,
18   IdException, HttpThread, IdHTTP, LogDownload,
19   ScriptConsts, DateUtils, BottleChainRule, BottleChainEvent,
20   SakuraSeekerInstance, HEditor, HTSearch, heClasses, heFountain,
21   SakuraScriptFountain, SppList, SurfacePreview, XDOM_2_3_J3, SsPlayTime,
22   RegexUtils, StrReplace, StrReplaceDialog, IdAntiFreezeBase;
23
24 type
25   TSurfacePreviewType = (spHint, spEditor);
26
27   TfrmSender = class(TForm)
28     MainMenu: TMainMenu;
29     mnFile: TMenuItem;
30     mnExit: TMenuItem;
31     mnRegister: TMenuItem;
32     mnStart: TMenuItem;
33     mnScript: TMenuItem;
34     StatusBar: TStatusBar;
35     mnHelp: TMenuItem;
36     mnAbout: TMenuItem;
37     mnEditConst: TMenuItem;
38     ActionList: TActionList;
39     mnPopUp: TPopupMenu;
40     mnPopPaste: TMenuItem;
41     mnPopCut: TMenuItem;
42     mnPopCopy: TMenuItem;
43     mnPopSelectAll: TMenuItem;
44     N6: TMenuItem;
45     mnPopConst: TMenuItem;
46     mnEdit: TMenuItem;
47     mnPaste: TMenuItem;
48     mnCopy: TMenuItem;
49     mnCut: TMenuItem;
50     mnSelectAll: TMenuItem;
51     TaskTray: TTaskTray;
52     ApplicationEvents: TApplicationEvents;
53     mnPopUpTaskTray: TPopupMenu;
54     mnTaskStart: TMenuItem;
55     mnTaskEnd: TMenuItem;
56     mnTaskRestore: TMenuItem;
57     mnTaskNewMessage: TMenuItem;
58     actStart: TAction;
59     actStop: TAction;
60     N8: TMenuItem;
61     mnTaskExit: TMenuItem;
62     actSend: TAction;
63     actConfirm: TAction;
64     actClear: TAction;
65     mnSend: TMenuItem;
66     mnConfirm: TMenuItem;
67     mnClear: TMenuItem;
68     imgIcon: TImageList;
69     mnPopupConst: TPopupMenu;
70     actEditConst: TAction;
71     mnView: TMenuItem;
72     mnShowToolBar: TMenuItem;
73     mnShowConstBar: TMenuItem;
74     ConstBarMenu: TMainMenu;
75     ToolBar: TToolBar;
76     tbtnClear: TToolButton;
77     tbtnConfirm: TToolButton;
78     tbtnSend: TToolButton;
79     tbtnSeparator: TToolButton;
80     tbtnStart: TToolButton;
81     tbtnSeparator2: TToolButton;
82     tbtnInsertConst: TToolButton;
83     ConstMenuBar: TMenuBar;
84     mnGoToHP: TMenuItem;
85     LabelTimer: TTimer;
86     mnCopyAll: TMenuItem;
87     actCopyAll: TAction;
88     actCopyAllNoReturn: TAction;
89     mnCopyAllNoReturn: TMenuItem;
90     mnPopCopyAll: TMenuItem;
91     mnPopCopyAllNoReturn: TMenuItem;
92     actSetting: TAction;
93     tbtnSetting: TToolButton;
94     mnStayOnTop: TMenuItem;
95     mnSetting: TMenuItem;
96     actExitClient: TAction;
97     SsParser: TSsParser;
98     tbtnEditConst: TToolButton;
99     actClearBottles: TAction;
100     mnClearBottles: TMenuItem;
101     MediaPlayer: TMediaPlayer;
102     mnGetNewId: TMenuItem;
103     actNextChannel: TAction;
104     actPrevChannel: TAction;
105     N2: TMenuItem;
106     mnNextChannel: TMenuItem;
107     mnPrevChannel: TMenuItem;
108     actShowLog: TAction;
109     N3: TMenuItem;
110     tbtnShowLog: TToolButton;
111     tbtnSleep: TToolButton;
112     actSleep: TAction;
113     N1: TMenuItem;
114     mnSleep: TMenuItem;
115     mnTaskSleep: TMenuItem;
116     pnlEditor: TPanel;
117     tabChannel: TTabControl;
118     pnlPanel: TPanel;
119     lblMessage: TLabel;
120     cbxTargetGhost: TComboBox;
121     actVoteMessage: TAction;
122     mnPopUpChannelTab: TPopupMenu;
123     mnLeaveThisChannel: TMenuItem;
124     N4: TMenuItem;
125     mnGotoVote: TMenuItem;
126     mnGoToHelp: TMenuItem;
127     btnSend: TButton;
128     btnConfirm: TButton;
129     btnClear: TButton;
130     mnExitAllChannels: TMenuItem;
131     actAgreeMessage: TAction;
132     IdSLPP20: TIdSLPP20;
133     btnIfGhost: TButton;
134     actPrevGhost: TAction;
135     actNextGhost: TAction;
136     mnPrevGhost: TMenuItem;
137     mnNextGhost: TMenuItem;
138     actResetGhost: TAction;
139     mnResetGhost: TMenuItem;
140     timDisconnectCheckTimer: TTimer;
141     DirectSstp: TDirectSstp;
142     actDownloadLog: TAction;
143     actFMOExplorer: TAction;
144     tbtnFMOExplorer: TToolButton;
145     mnFMOExplorer: TMenuItem;
146     mnLine: TMenuItem;
147     actInsertCue: TAction;
148     SakuraScriptFountain: TSakuraScriptFountain;
149     memScript: TEditor;
150     actCopy: TAction;
151     actPaste: TAction;
152     actCut: TAction;
153     actSelectAll: TAction;
154     actRecallScriptBuffer: TAction;
155     N5: TMenuItem;
156     mnRecallScriptBuffer: TMenuItem;
157     tbtnEditorPreview: TToolButton;
158     actEditorPreview: TAction;
159     mnEditorPreview: TMenuItem;
160     actResetPlugins: TAction;
161     N7: TMenuItem;
162     mnResetPlugins: TMenuItem;
163     actReplace: TAction;
164     N10: TMenuItem;
165     mnReplace: TMenuItem;
166     actSendToEditor: TAction;
167     actSendToLogWindow: TAction;
168     mnSendLogWindow: TMenuItem;
169     actDeleteLogItem: TAction;
170     actAbout: TAction;
171     actEditCopy: TEditCopy;
172     tbtnSendToLogWindow: TToolButton;
173     SsPlayTime: TSsPlayTime;
174     actUndo: TAction;
175     actRedo: TAction;
176     mnUndo: TMenuItem;
177     mnRedo: TMenuItem;
178     N9: TMenuItem;
179     procedure actConfirmExecute(Sender: TObject);
180     procedure FormCreate(Sender: TObject);
181     procedure FormDestroy(Sender: TObject);
182     procedure actSendExecute(Sender: TObject);
183     procedure HTTPSuccess(Sender: TObject);
184     procedure HTTPFailure(Sender: TObject);
185     procedure actStartClick(Sender: TObject);
186     procedure actStopExecute(Sender: TObject);
187     procedure FormShow(Sender: TObject);
188     procedure actAboutClick(Sender: TObject);
189     procedure actExitClientExecute(Sender: TObject);
190     procedure actClearExecute(Sender: TObject);
191     procedure memScriptChange(Sender: TObject);
192     procedure mnStayOnTopClick(Sender: TObject);
193     procedure actEditConstExecute(Sender: TObject);
194     procedure mnTaskBarClick(Sender: TObject);
195     procedure FormClose(Sender: TObject; var Action: TCloseAction);
196     procedure ApplicationEventsMinimize(Sender: TObject);
197     procedure ApplicationEventsRestore(Sender: TObject);
198     procedure mnTaskRestoreClick(Sender: TObject);
199     procedure TaskTrayDblClick(Seft: TObject; Button: TMouseButton);
200     procedure FormActivate(Sender: TObject);
201     procedure mnTaskNewMessageClick(Sender: TObject);
202     procedure ApplicationEventsHint(Sender: TObject);
203     procedure memScriptKeyDown(Sender: TObject; var Key: Word;
204       Shift: TShiftState);
205     procedure mnShowToolBarClick(Sender: TObject);
206     procedure mnShowConstBarClick(Sender: TObject);
207     procedure mnGoToHPClick(Sender: TObject);
208     procedure LabelTimerTimer(Sender: TObject);
209     procedure actCopyAllExecute(Sender: TObject);
210     procedure actCopyAllNoReturnExecute(Sender: TObject);
211     procedure Slpp20SlppEvent(Sender: TObject; EventType: TIdSlppEventType;
212       const Param: String);
213     procedure actSettingExecute(Sender: TObject);
214     procedure memScriptKeyPress(Sender: TObject; var Key: Char);
215     procedure Slpp20Disconnect(Sender: TObject);
216     procedure actClearBottlesExecute(Sender: TObject);
217     procedure SakuraSeekerDetectResultChanged(Sender: TObject);
218     procedure mnGetNewIdClick(Sender: TObject);
219     procedure tabChannelChange(Sender: TObject);
220     procedure actPrevChannelExecute(Sender: TObject);
221     procedure actNextChannelExecute(Sender: TObject);
222     procedure cbxTargetGhostDropDown(Sender: TObject);
223     procedure actShowLogExecute(Sender: TObject);
224     procedure actSleepExecute(Sender: TObject);
225     procedure actVoteMessageExecute(Sender: TObject);
226     procedure tabChannelContextPopup(Sender: TObject; MousePos: TPoint;
227       var Handled: Boolean);
228     procedure mnLeaveThisChannelClick(Sender: TObject);
229     procedure mnGotoVoteClick(Sender: TObject);
230     procedure tabChannelMouseMove(Sender: TObject; Shift: TShiftState; X,
231       Y: Integer);
232     procedure mnGoToHelpClick(Sender: TObject);
233     procedure tabChannelMouseDown(Sender: TObject; Button: TMouseButton;
234       Shift: TShiftState; X, Y: Integer);
235     procedure tabChannelDragOver(Sender, Source: TObject; X, Y: Integer;
236       State: TDragState; var Accept: Boolean);
237     procedure tabChannelDragDrop(Sender, Source: TObject; X, Y: Integer);
238     procedure tabChannelEndDrag(Sender, Target: TObject; X, Y: Integer);
239     procedure cbxTargetGhostDrawItem(Control: TWinControl; Index: Integer;
240       Rect: TRect; State: TOwnerDrawState);
241     procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
242     procedure actAgreeMessageExecute(Sender: TObject);
243     procedure actPrevGhostExecute(Sender: TObject);
244     procedure actNextGhostExecute(Sender: TObject);
245     procedure actResetGhostExecute(Sender: TObject);
246     procedure timDisconnectCheckTimerTimer(Sender: TObject);
247     procedure actDownloadLogExecute(Sender: TObject);
248     procedure cbxTargetGhostChange(Sender: TObject);
249     procedure actFMOExplorerExecute(Sender: TObject);
250     procedure actInsertCueExecute(Sender: TObject);
251     procedure FormResize(Sender: TObject);
252     procedure actCopyExecute(Sender: TObject);
253     procedure actPasteExecute(Sender: TObject);
254     procedure actCutExecute(Sender: TObject);
255     procedure actSelectAllExecute(Sender: TObject);
256     procedure memScriptMouseMove(Sender: TObject; Shift: TShiftState; X,
257       Y: Integer);
258     procedure actRecallScriptBufferExecute(Sender: TObject);
259     procedure actEditorPreviewExecute(Sender: TObject);
260     procedure actResetPluginsExecute(Sender: TObject);
261     procedure IdSLPP20Connect(Sender: TObject);
262     procedure actReplaceExecute(Sender: TObject);
263     procedure actSendToEditorExecute(Sender: TObject);
264     procedure actSendToLogWindowExecute(Sender: TObject);
265     procedure memScriptDragOver(Sender, Source: TObject; X, Y: Integer;
266       State: TDragState; var Accept: Boolean);
267     procedure memScriptDragDrop(Sender, Source: TObject; X, Y: Integer);
268     procedure actDeleteLogItemExecute(Sender: TObject);
269     procedure memScriptSelectionChange(Sender: TObject; Selected: Boolean);
270     procedure actUndoExecute(Sender: TObject);
271     procedure actRedoExecute(Sender: TObject);
272     procedure IdSLPP20ConnectFailed(Sender: TObject);
273   private
274     FSleeping: boolean;  // \94z\91\97\83X\83\8a\81[\83v\92\86\82©\82Ç\82¤\82©
275     FStatusText: String;
276     FConnecting: boolean;
277     FAdded: boolean;
278     FBooted: boolean; //\8f\89\89ñ\8bN\93®\92Ê\90M\97p
279     FEndSession: Boolean; // Windows\8fI\97¹\82ð\8c\9f\92m\82µ\82Ätrue\82É\82È\82é
280     FOriginalCaption: String;
281     FAutoAddAfterGetChannel: boolean; //\83`\83\83\83\93\83l\83\8b\8eæ\93¾\8cã\82É\83_\83C\83A\83\8d\83O\82È\82µ\82É
282                                       //\83`\83\83\83\93\83l\83\8b\82É\8eQ\89Á\82·\82é\82©\82Ç\82¤\82©
283     FConstDir: String;
284     FSppDir: String;
285     //
286     FNowChannel: String; //\8c»\8dÝ\91I\91ð\82³\82ê\82Ä\82¢\82é\83`\83\83\83\93\83l\83\8b
287     JoinChannelsBackup: TStringList; //\88ê\8e\9e\8eg\97p
288     //
289     FScriptModified: boolean; // \83X\83N\83\8a\83v\83g\82ª\95Ï\8dX\82³\82ê\82Ä\82¢\82é\82©\82Ç\82¤\82©\81B
290                               // \83\8d\81[\83J\83\8b\8am\94F\8b­\90§\97p\83t\83\89\83O\81BTRichEdit.Modified\82Í
291                               //\95Ê\82Ì\97p\93r\82Å\8eg\82Á\82Ä\82¢\82é\82Ì\82Å\8eg\82¦\82È\82¢
292     //
293     FDragTabIndex: integer; //\83^\83u\83h\83\89\83b\83O\83h\83\8d\83b\83v\8aÖ\98A
294     FDragTabDest: integer;  //\83h\83\8d\83b\83v\82·\82é\88Ê\92u(\82·\82®\89E\82É\82­\82é\83^\83u\82Ì\83C\83\93\83f\83b\83N\83X)
295     //
296     FBottleSstp: TBottleSstp; // \8dÄ\91\97\83v\83\8d\83O\83\89\83\80
297     //
298     FHttp: THTTPDownloadThread; //HTTP\83_\83E\83\93\83\8d\81[\83h\83X\83\8c\83b\83h(\83C\83\93\83X\83^\83\93\83X\82Í1\8cÂ\82Ì\82Ý)
299     FBeginConnectFailCount: integer; //\89½\93x\82à\90Ú\91±\8e¸\94s\82µ\82½\82ç\83\8a\83g\83\89\83C\92\86\8e~
300     //
301     FVisiblePreviewGhost: String;
302     FVisiblePreviewSurface: integer; //\83T\81[\83t\83B\83X\83v\83\8c\83r\83\85\81[\82Å\8c©\82¦\82Ä\82¢\82é\82à\82Ì
303     FVisibleMenuItem: TMenuItem; //\83N\83\8a\83b\83N\82³\82ê\82½\83\81\83j\83\85\81[\83A\83C\83e\83\80\81B
304                                  //\83T\81[\83t\83B\83X\83v\83\8c\83r\83\85\81[\82ª\83\81\83j\83\85\81[\82Ì\89º\82É
305                                  //\89B\82ê\82È\82¢\82æ\82¤\82É\95\\8e¦\82³\82ê\82Ä\82¢\82é\82à\82Ì\82ð\8bL\89¯\82µ\82Ä\82¨\82­
306     //
307     FTargetGhostExpand: boolean; //\83S\81[\83X\83g\91I\91ð\83{\83b\83N\83X\82ª\81A
308                                  //\88ê\8e\9e\93I\82É\91S\95\94\95\\8e¦\82³\82ê\82Ä\82¢\82é\82©\82Ç\82¤\82©\82Ì\83t\83\89\83O
309     //
310     FScriptBuffer: TObjectList;  //\83X\83N\83\8a\83v\83g\83N\83\8a\83A\83o\83b\83t\83@
311     //
312     FWM_TaskBarCreated: WORD; // \83^\83X\83N\83o\81[\93o\98^\97p\83E\83B\83\93\83h\83E\83\81\83b\83Z\81[\83WID
313     //
314     procedure SetStatusText(const Value: String);
315     procedure SetSleeping(const Value: boolean);
316     procedure YenETrans;
317     procedure SetConnecting(const Value: boolean);
318     procedure SetAdded(const Value: boolean);
319     procedure mnConstClick(Sender: TObject);
320     procedure mnConstGroupClick(Sender: TObject);
321     property Added: boolean read FAdded write SetAdded;
322     property Sleeping: boolean read FSleeping write SetSleeping;
323     property StatusText: String read FStatusText write SetStatusText;
324     function GetScriptText: String;
325     procedure ChangeTaskIcon;
326     procedure ShowHintLabel(const Mes: String; Col: TColor = clBlue);
327     procedure UpdateLayout;
328     procedure DispatchBottle(EventType: TIdSlppEventType; Dat: THeadValue);
329     //\83`\83\83\83\93\83l\83\8b\8aÖ\8cW
330     procedure UpdateChannelInfo(Dat: THeadValue);
331     procedure UpdateJoinChannelList(Dat: THeadValue);
332     procedure NoLuidError;
333     procedure UpdateIfGhostBox;
334     function BuildMenuConditionCheck(const IfGhost, Ghost: String): boolean;
335     procedure BuildMenu(Root: TMenuItem; Simple: boolean);
336     procedure PlaySound(const FileName: String);
337     //TBottleSstp\8aÖ\8cW\83C\83x\83\93\83g\83n\83\93\83h\83\89
338     procedure BottleSstpResendCountChange(Sender: TObject);
339     procedure BottleSstpResendTrying(Sender: TObject; MID: String);
340     procedure BottleSstpResendEnd(Sender: TObject; MID: String);
341     function IsSurfaceTag(const Script: String; var ID: integer): boolean;
342     procedure DoSurfacePreview(Surface: integer; const Kind:
343       TSurfacePreviewType);
344     function GetSurfacePreviewPositionHint(w, h: integer): TPoint;
345     function GetSurfacePreviewPositionScriptPoint(w, h: integer): TPoint;
346     procedure EditorPreview;
347     // \83^\83O\82Ì\95\8e\9a\97ñ\82ð\95Ï\8a·\82·\82é
348     function TagReplace(Script: String;
349       Before, After: array of String): String; overload;
350     function TagReplace(Script: String;
351       Before, After: TStrings): String; overload;
352     // \83T\81[\83t\83B\83X\82ð\95Ï\8a·\82·\82é
353     function ReplaceSurface(Script: String; Params: TCollection): String;
354     procedure ClearEditor;
355     procedure CopyFromLogToEditor(Log: TLogItem);
356     //
357     procedure AppendTextLog(const FileName, Line: String);
358     procedure AppendXMLLog(const FileName: String; Args: THeadValue);
359   protected
360     procedure WndProc(var Message: TMessage); override;
361     procedure WMQueryEndSession(var msg: TWMQueryEndSession);
362       message WM_QUERYENDSESSION;
363   public
364     function DoTrans(var Script: String;
365       Options: TScriptTransOptions): String; overload;
366     function DoTrans(var Script: String;
367       Options: TScriptTransOptions; out FoundURL: boolean): String; overload;
368     function ScriptTransForSSTP(const Script: String;
369       out Error: String): String; overload;
370     procedure BeginConnect;
371     procedure RetryBeginConnect;
372     procedure EndConnect;
373     procedure ConstructMenu(Simple: boolean);
374     property Connecting: boolean read FConnecting write SetConnecting;
375     property BottleSstp: TBottleSstp read FBottleSstp;
376     function GhostNameToSetName(const Ghost: String): String;
377     procedure PostCommand(const Command: array of String); overload;
378     procedure PostCommand(Command: TStrings); overload;
379     procedure PostSetChannel(Channels: TStrings);
380     procedure SaveChainRuleList;
381   end;
382
383
384 var
385   frmSender: TfrmSender;
386
387 const
388   PanelConnecting = 0;  //\81u\90Ú\91±\92\86\81v\95\\8e¦\97p
389   PanelBytes      = 1;  //\81\9b\81\9b\83o\83C\83g
390   PanelCount      = 2;  //Local Proxy\81A\8c»\8dÝ\81\9b\8c\8f\91Ò\82¿
391   PanelMembers    = 3;  //\81\9b\81\9b\90l
392   PanelStatus     = 4;  //SSTP Bottle\83T\81[\83o\82É\93o\98^\82³\82ê\82Ä\82¢\82Ü\82·\81c\82È\82Ç
393
394   IconConnected    = 17;
395   IconDisconnected = 18;
396   IconSleep        = 19;
397   IconSleepDisconnected = 20;
398
399   WarningColor = clRed;
400
401   SendButtonLongHint = 'Bottle\82Ì\91\97\90M';
402
403 function Token(const Str: String; const Delimiter: char;
404   const Index: integer): String;
405
406 function StringReplaceEx(const Before: String; List: THeadValue): String;
407
408 implementation
409
410 uses SendConfirm, SettingForm, ChannelListForm, LogForm,
411   MessageBox, FMOExplorer, EditorTalkShow;
412
413 {$R *.DFM}
414
415 // \92P\8f\83\82É\83o\83C\83g\92P\88Ê\82Å\95\8e\9a\97ñ\82ð\8c©\82Ä\82¢\82«\95ª\89ð\82·\82é\83\86\81[\83e\83B\83\8a\83e\83B\8aÖ\90\94
416 function Token(const Str: String; const Delimiter: char;
417   const Index: integer): String;
418 var i, c, len: integer;
419 begin
420   i := 1;
421   c := 0;
422   len := length(Str);
423   Result := '';
424   while i <= len do begin
425     if (Str[i] = Delimiter) and (StrByteType(PChar(Str), i) <> mbTrailByte) then begin
426       Inc(c);
427       if c > Index then Break;
428     end else if c = Index then Result := Result + Str[i];
429     Inc(i);
430   end;
431 end;
432
433 // \95\8e\9a\97ñ\82ð\92u\82«\8a·\82¦\82é\83\86\81[\83e\83B\83\8a\83e\83B\8aÖ\90\94
434 function StringReplaceEx(const Before: String; List: THeadValue): String;
435 var
436   i, MinPos, MinKey, p: integer;
437   Work: String;
438 begin
439   Work := Before;
440   Result := '';
441   MinKey := -1;
442   while Work <> '' do
443   begin
444     MinPos := -1;
445     for i := 0 to List.Count-1 do
446     begin
447       p := Pos(List.KeyAt[i], Work);
448       if (p > 0) and ((p < MinPos) or (MinPos < 0)) then
449       begin
450         MinPos := p;
451         MinKey := i;
452       end;
453     end;
454     if MinPos < 0 then
455     begin
456       Result := Result + Work;
457       Break;
458     end else
459     begin
460       Result := Result + Copy(Work, 1, MinPos-1) + List.ValueAt[MinKey];
461       Delete(Work, 1, (MinPos - 1) + Length(List.KeyAt[MinKey]));
462     end;
463   end;
464 end;
465
466 {TfrmSender}
467
468 procedure TfrmSender.actConfirmExecute(Sender: TObject);
469 var
470   AScript, Err, AGhost: String;
471   Item: TLogItem;
472   Choice: integer;
473 begin
474   // Partial Confirmation
475   if memScript.SelText <> '' then
476   begin
477     Choice := 0;
478     if not Pref.AutoPartialConfirm then
479       if not MultipleChoiceEdit('\8am\94F', ['\91I\91ð\95\94\95ª\82Ì\82Ý', '\83X\83N\83\8a\83v\83g\91S\91Ì'], Choice) then
480         Exit;
481     if Choice = 0 then
482     begin
483       AScript := memScript.SelText;
484       AScript := StringReplace(Pref.PartialConfirmFormat, '|', AScript, []);
485     end else
486       AScript := GetScriptText;
487   end else
488     AScript := GetScriptText;
489   AScript := StringReplace(AScript, #13#10, '', [rfReplaceAll]);
490
491   if Length(AScript) = 0 then Exit;
492   YenETrans;
493   AScript := ScriptTransForSSTP(AScript, Err);
494   if Err <> '' then
495   begin
496     ShowMessage(Err);
497     Exit;
498   end;
499
500   if cbxTargetGhost.ItemIndex > 0 then
501     AGhost := cbxTargetGhost.Text
502   else if FNowChannel <> '' then
503     AGhost := ChannelList.Channel[FNowChannel].Ghost
504   else
505     AGhost := '';
506
507   if Pref.IgnoreTimeCritical then
508     AScript := TagReplace(AScript, ['\t'], ['']);
509
510   Item := TLogItem.Create;
511   try
512     with Item do
513     begin
514       LogType := ltBottle;
515       Script := AScript;
516       Channel := '\81y\8am\94F\81z';
517       Ghost := AGhost;
518     end;
519     BottleSstp.Unshift(Item);
520   except
521     Item.Free;
522   end;
523
524   FScriptModified := false;
525 end;
526
527 procedure TfrmSender.FormCreate(Sender: TObject);
528 var Str: TStringList;
529 begin
530   FScriptBuffer := TObjectList.Create(true);
531
532   SakuraSeeker.OnDetectResultChanged := SakuraSeekerDetectResultChanged;
533   FConstDir := ExtractFileDir(Application.ExeName)+'\consts';
534   ScriptConstList.LoadFromDir(FConstDir);
535   FSppDir := ExtractFileDir(Application.ExeName)+'\spp';
536   Spps.LoadFromDirectory(FSppDir);
537   ConstructMenu(false);
538
539   Str := TStringList.Create;
540   try
541     try
542       Str.LoadFromFile(ExtractFilePath(Application.ExeName)+'rule.txt');
543       BottleChainRuleList := StringToComponent(Str.Text) as TBottleChainRuleList;
544     except
545       try
546         Str.LoadFromFile(ExtractFilePath(Application.ExeName)+'defrule.txt');
547         BottleChainRuleList := StringToComponent(Str.Text) as TBottleChainRuleList;
548       except
549         Showmessage('defrule.txt\93Ç\82Ý\8d\9e\82Ý\92\86\82É\92v\96½\93I\83G\83\89\81[\82ª\94­\90\82µ\82Ü\82µ\82½\81Bdefrule.txt\82ð\8dÄ\83C\83\93\83X\83g\81[\83\8b\82µ\82Ä\82­\82¾\82³\82¢\81B');
550         Application.Terminate;
551         Application.ProcessMessages;
552         Exit;
553       end;
554     end;
555   finally
556     Str.Free;
557   end;
558
559   FOriginalCaption := Self.Caption;
560
561   UpdateLayout;
562   mnShowToolBar.Checked := Pref.ShowToolBar;
563   mnShowConstBar.Checked := Pref.ShowConstBar;
564   if Pref.StayOnTop then begin
565     FormStyle := fsStayOnTop;
566     mnStayOnTop.Checked := true;
567   end else begin
568     FormStyle := fsNormal;
569     mnStayOnTop.Checked := false;
570   end;
571
572   // URL\83W\83\83\83\93\83v\90æ\82ð\83q\83\93\83g\95\8e\9a\97ñ\82Æ\82µ\82Ä\90Ý\92è
573   mnGoToHP.Hint := Pref.HomePage;
574   mnGotoVote.Hint := Pref.VotePage;
575   mnGotoHelp.Hint := Pref.HelpPage;
576
577   mnGetNewId.Enabled := (Pref.LUID = '');
578
579   // \82³\82­\82ç\83X\83N\83\8a\83v\83g\89ð\90Í\83p\83^\81[\83\93\82ð\93Ç\82Ý\8d\9e\82Ý
580   try
581     SsParser.TagPattern.LoadFromFile(ExtractFilePath(Application.Exename) + 'tagpat.txt');
582     SsParser.MetaPattern.LoadFromFile(ExtractFilePath(Application.ExeName) + 'metapat.txt');
583   except
584     ShowMessage('tagpat.txt, metapat.txt\82ª\8c©\82Â\82©\82è\82Ü\82¹\82ñ\81B');
585     Application.Terminate;
586   end;
587
588   // \8dÄ\90\8e\9e\8aÔ\90\84\92è\83R\83\93\83|\81[\83l\83\93\83g\82É\83p\83\89\83\81\81[\83^\82ð\8ew\92è
589   SsPlayTime.PlayTimeParams := Pref.PlayTimeParams;
590
591   // \83\81\83C\83\93\83E\83B\83\93\83h\83E\82Ì\88Ê\92u\82Æ\83T\83C\83Y\82ð\95\9c\8bA
592   with Pref.SenderWindowPosition do begin
593     Self.Left   := Left;
594     Self.Top    := Top;
595     Self.Width  := Right - Left + 1;
596     Self.Height := Bottom - Top + 1;
597   end;
598
599   // \83^\83X\83N\83o\81[\82Ì\8dÄ\8bN\93®(Explorer\82ª\97\8e\82¿\82½\82Æ\82«)\82ð\8c\9f\8fo\82·\82é
600   FWM_TaskBarCreated := RegisterWindowMessage('TaskBarCreated');
601
602   // \83X\83N\83\8a\83v\83g\95\8e\9a\97ñ\82Ì\8f\89\8aú\89»
603   actClearExecute(Sender);
604   // \83^\83X\83N\83g\83\8c\83C\82É\83A\83C\83R\83\93\82ð\92Ç\89Á
605   ChangeTaskIcon;
606   // \83`\83\83\83\93\83l\83\8b\8eQ\89Á\8aÖ\8cW\82Ì\83^\83u\82Ì\8f\88\97\9d\82È\82Ç(\83`\83\83\83\93\83l\83\8b\95s\8eQ\89Á\82Å\8f\89\8aú\89»)
607   UpdateJoinChannelList(nil);
608
609   // SSTP\8dÄ\91\97\83I\83u\83W\83F\83N\83g
610   FBottleSstp := TBottleSstp.Create(false);
611   with FBottleSstp do begin
612     OnResendCountChange := BottleSstpResendCountChange;
613     OnResendTrying := BottleSstpResendTrying;
614     OnResendEnd := BottleSstpResendEnd;
615   end;
616 end;
617
618 procedure TfrmSender.FormDestroy(Sender: TObject);
619 begin
620   if FScriptBuffer <> nil then
621     FScriptBuffer.Free;
622
623   if FBottleSstp <> nil then begin
624     FBottleSstp.Terminate;
625     FBottleSstp.Free;
626   end;
627
628   with Pref.SenderWindowPosition do begin
629     Left   := Self.Left;
630     Top    := Self.Top;
631     Right  := Self.Left + Self.Width - 1;
632     Bottom := Self.Top + Self.Height - 1;
633   end;
634
635   if JoinChannelsBackup <> nil then JoinChannelsBackup.Free;
636
637   ScriptConstList.Save;
638
639   SaveChainRuleList;
640   BottleChainRuleList.Free;
641
642 end;
643
644
645 procedure TfrmSender.SetConnecting(const Value: boolean);
646 begin
647   FConnecting := Value;
648   if Value then begin
649     StatusBar.Panels[PanelConnecting].Text := '\92Ê\90M\92\86';
650     actStart.Enabled := false;
651     actStop.Enabled := false;
652     actSend.Enabled := false;
653     actVoteMessage.Enabled := false;
654     actAgreeMessage.Enabled := false;
655     mnGetNewId.Enabled := false;
656     Screen.Cursor := crAppStart;
657   end else begin
658     StatusBar.Panels[PanelConnecting].Text := '';
659     actStart.Enabled := true;
660     actStop.Enabled := true;
661     actSend.Enabled := true;
662     frmLog.lvwLogChange(Self, nil, ctState);
663     mnGetNewId.Enabled := Pref.LUID = '';
664     Screen.Cursor := crDefault;
665   end;
666 end;
667
668 // \83\81\83b\83Z\81[\83W\91\97\90M
669 procedure TfrmSender.actSendExecute(Sender: TObject);
670 var Talk, Ghost: String;
671     Command: TStringList;
672     Err: String;
673     F: TextFile;
674 begin
675   if Length(GetScriptText) = 0 then begin
676     ShowMessage('\83X\83N\83\8a\83v\83g\82ª\8bó\82Å\82·\81B');
677     Exit;
678   end;
679
680   if Pref.LUID = '' then begin
681     NoLuidError;
682     Exit;
683   end;
684   if tabChannel.TabIndex < 0 then begin
685     ShowMessage('\83`\83\83\83\93\83l\83\8b\82É\8eQ\89Á\82µ\82Ä\82¢\82Ü\82¹\82ñ\81B'#13#10+
686       '\83\81\83j\83\85\81[\82©\82ç\81u\83`\83\83\83\93\83l\83\8b\8eQ\89Á\81v\82ð\8ds\82Á\82Ä\82­\82¾\82³\82¢\81B');
687     Exit;
688   end;
689   if ChannelList.Channel[FNowChannel].NoPost then begin
690     Beep;
691     ShowMessage(FNowChannel + ' \82Í\8eó\90M\90ê\97p\82Å\82·');
692     Exit;
693   end;
694
695   YenETrans;
696   Talk := StringReplace(GetScriptText, #13#10, '', [rfReplaceAll]);
697   Err := DoTrans(Talk, [toWarnMessySurface, toWarnCheck]);
698   if Err <> '' then begin
699     MessageDlg(Err, mtWarning, [mbOk], 0);
700     Exit;
701   end;
702
703   if Pref.NeedConfirmBeforeSend and FScriptModified then
704   begin
705     MessageDlg('\91\97\90M\91O\82É\83\8d\81[\83J\83\8b\8am\94F\82µ\82Ä\82­\82¾\82³\82¢\81B', mtError, [mbOk], 0);
706     Exit;
707   end;
708
709   if not Pref.NoConfirm then begin
710     if not SendConfirmDialog(FNowChannel, cbxTargetGhost.Text) then Exit;
711   end;
712
713   Ghost := '';
714   if cbxTargetGhost.ItemIndex > 0 then Ghost := cbxTargetGhost.Text;
715   Command := TStringList.Create;
716   try
717     with Command do begin
718       Add('Command: sendBroadcast');
719       Add('Channel: ' + FNowChannel);
720       Add('LUID: ' + Pref.LUID);
721       Add('Agent: ' + VersionString);
722       if Ghost <> '' then Add('Ghost: ' + Ghost);
723       Add('Talk: ' + Talk);
724     end;
725     PostCommand(Command);
726   finally
727     Command.Free;
728   end;
729
730   //\91\97\90M\83\8d\83O\95Û\91
731   AssignFile(F, ExtractFilePath(Application.ExeName) + SentLogFile);
732   if FileExists(ExtractFilePath(Application.ExeName) + SentLogFile) then
733     Append(F)
734   else
735     Rewrite(F);
736   WriteLn(F, Format('%s,%s,%s,%s', [FNowChannel, Ghost, FormatDateTime('yy/mm/dd hh:nn:ss', Now), Talk]));
737   Flush(F);
738   CloseFile(F);
739 end;
740
741 procedure TfrmSender.BeginConnect;
742 begin
743   if Pref.LUID = '' then begin
744     NoLuidError;
745     Exit;
746   end;
747   IdSlpp20.LUID := Pref.LUID;
748   self.Cursor := crHourGlass;
749   if IdSlpp20.Connected then IdSlpp20.Disconnect;
750   if Pref.UseHttpProxy then begin
751     IdSlpp20.Host := Pref.ProxyAddress;
752     IdSlpp20.Port := Pref.ProxyPort;
753     IdSlpp20.ProxyMode := true;
754   end else begin
755     IdSlpp20.Host := Pref.BottleServer;
756     IdSlpp20.Port := Pref.BottleServerPort;
757     IdSlpp20.ProxyMode := false;
758   end;
759   IdSlpp20.ConnectServer;
760   self.Cursor := crDefault;
761 end;
762
763 procedure TfrmSender.EndConnect;
764 begin
765   IdSlpp20.OnDisconnect := nil;
766   IdSlpp20.Disconnect;
767 end;
768
769 procedure TfrmSender.SetAdded(const Value: boolean);
770 begin
771   if FAdded = Value then Exit;
772   FAdded := Value;
773   if Value then begin
774     StatusText := 'SSTP Bottle \83T\81[\83o\82É\90Ú\91±\82³\82ê\82Ä\82¢\82Ü\82·';
775     ChangeTaskIcon;
776   end else begin
777     StatusText := '\83T\81[\83o\82Æ\82Ì\90Ú\91±\82ª\90Ø\82ê\82Ä\82¢\82Ü\82·!';
778     ChangeTaskIcon;
779     ShowHintLabel('SSTP Bottle\83T\81[\83o\82©\82ç\90Ø\92f\82³\82ê\82Ü\82µ\82½!', WarningColor);
780   end;
781 end;
782
783 procedure TfrmSender.HTTPSuccess(Sender: TObject);
784 var Str, ResStr, Command: String;
785     HeadValue: THeadValue;
786     i: integer;
787     SetChannel: TStringList;
788 begin
789   Connecting := false;
790   Str := (Sender as THttpDownloadThread).RecvString;
791   HeadValue := nil;
792   try
793     try
794       HeadValue := THeadValue.Create(Str);
795     except
796       ShowMessage('SSTP Bottle\83T\81[\83o\82ª\89ð\90Í\82Å\82«\82È\82¢\83G\83\89\81[\82ð\95Ô\82µ\82Ü\82µ\82½\81B');
797       Exit;
798     end;
799     Command := HeadValue['Command'];
800     ResStr  := HeadValue['Result'];
801     if ResStr = 'Err' then begin
802       if HeadValue['ExtraMessage'] <> '' then begin
803         Beep;
804         ShowMessage('SSTP Bottle\83T\81[\83o\82ª\8e\9f\82Ì\83G\83\89\81[\82ð\95Ô\82µ\82Ü\82µ\82½:'#13#10 +
805                      HeadValue['ExtraMessage']);
806       end else begin
807         Beep;
808         ShowMessage('SSTP Bottle\83T\81[\83o\82ª\89½\82ç\82©\82Ì\83G\83\89\81[\82ð\95Ô\82µ\82Ü\82µ\82½\81B');
809       end;
810     end;
811     if (Command = 'sendBroadcast') and (ResStr = 'OK') then begin
812       ShowHintLabel(HeadValue['Channel'] + ' \82Ì ' + HeadValue['SentNum'] +
813                     '\90l\82É\91\97\90M\82µ\82Ü\82µ\82½');
814       //\83S\81[\83X\83g\82ð\83f\83t\83H\83\8b\83g\82É\96ß\82·
815       if Pref.ResetIfGhostAfterSend then begin
816         actResetGhostExecute(Self);
817       end;
818       //\83X\83N\83\8a\83v\83g\82ð\83N\83\8a\83A
819       if Pref.ClearAfterSend then begin
820         actClear.Execute;
821       end;
822     end else if (Command = 'sendBroadcast') and (ResStr <> 'OK') then begin
823       ShowHintLabel('\83\81\83b\83Z\81[\83W\82ð\91\97\90M\82Å\82«\82Ü\82¹\82ñ\82Å\82µ\82½', WarningColor);
824     end;
825     if (Command = 'getNewId') then begin
826       if ResStr = 'OK' then begin
827         Pref.LUID := HeadValue['NewID'];
828         ShowHintLabel('LUID\8eæ\93¾\8a®\97¹\81B');
829         frmMessageBox.ShowMessage('\8f\89\89ñ\8bN\93®\82Ì\82½\82ß\81A' +
830           'SSTP Bottle\83T\81[\83o\90Ú\91±\97p\82ÌID(LUID)\82ð\90V\8bK\8eæ\93¾\82µ\82Ü\82µ\82½\81B'#13#10 +
831           'LUID: ' + Pref.LUID +  #13#10 +
832           '\90Ý\92è\83t\83@\83C\83\8b\82ð\8dí\8f\9c\82·\82é\82±\82Æ\82Å\81ALUID\82Í\8e©\97R\82É\8eæ\93¾\82Å\82«\82Ü\82·\82ª\81A' +
833           'LUID\82Ì\8eg\97p\8eÀ\90Ñ\82É\89\9e\82\82Ä\93Á\93T\82ª\82 \82é\82©\82à\82µ\82ê\82Ü\82¹\82ñ\82Ì\82Å\81A' +
834           '\8fo\97\88\82é\82¾\82¯\93¯\82\82à\82Ì\82ð\8eg\82Á\82Ä\82­\82¾\82³\82¢\81B\8fÚ\8d×\82Í\83w\83\8b\83v\82ð\82²\97\97\82­\82¾\82³\82¢\81B');
835         mnGetNewId.Enabled := false;
836         BeginConnect;
837       end else begin
838         ShowHintLabel('LUID\8eæ\93¾\82É\8e¸\94s\82µ\82Ü\82µ\82½');
839       end;
840     end;
841     if (Command = 'voteMessage') then begin
842       if ResStr = 'OK' then begin
843         ShowHintLabel('\83\81\83b\83Z\81[\83W\82É\93\8a\95[/\93¯\88Ó\82µ\82Ü\82µ\82½\81B\95[\90\94: ' + HeadValue['Votes']);
844       end;
845     end;
846     if (Command = 'getChannels') and (ResStr = 'OK') then begin
847       UpdateChannelInfo(HeadValue);
848       SetChannel := nil;
849       try
850         if FAutoAddAfterGetChannel then begin
851           SetChannel := TStringList.Create;
852           if JoinChannelsBackup <> nil then begin
853             //\88ê\92U\83`\83\83\83\93\83l\83\8b\8eQ\89Á\82É\90¬\8c÷\82µ\82½\8cã\82È\82ç\8dÅ\8cã\82É\8eQ\89Á\82µ\82Ä\82¢\82½\83`\83\83\83\93\83l\83\8b
854             SetChannel.Assign(JoinChannelsBackup);
855           end else begin
856             //\8a®\91S\82É\8f\89\89ñ\8bN\93®\82Ì\8fê\8d\87\82Í\83v\83\8c\83t\83@\83\8c\83\93\83X\82©\82ç\93o\98^\95ª\82ð\8eæ\93¾
857             for i := 0 to Pref.AutoJoinChannels.Count-1 do begin
858               if ChannelList.Channel[Pref.AutoJoinChannels[i]] <> nil then
859                 SetChannel.Add(Pref.AutoJoinChannels[i]);
860             end;
861           end;
862         end else begin
863           Application.CreateForm(TfrmChannelList, frmChannelList);
864           try
865             if frmChannelList.Execute(ChannelList, JoinChannels) then begin
866               SetChannel := TStringList.Create;
867               SetChannel.Assign(frmChannelList.JoinList);
868             end;
869           finally
870             frmChannelList.Release;
871           end;
872         end;
873         if SetChannel <> nil then PostSetChannel(SetChannel);
874       finally
875         if SetChannel <> nil then FreeAndNil(SetChannel);
876       end;
877     end;
878     if (Command = 'setChannels') then begin
879       if ResStr <> 'OK' then begin
880         Beep;
881         ShowMessage('\83`\83\83\83\93\83l\83\8b\90Ý\92è\82É\8e¸\94s\82µ\82Ü\82µ\82½\81B\82à\82¤\88ê\93x\93o\98^\82µ\82È\82¨\82µ\82Ä\82­\82¾\82³\82¢');
882         ShowHintLabel('\83`\83\83\83\93\83l\83\8b\90Ý\92è\82É\8e¸\94s\82µ\82Ü\82µ\82½', WarningColor);
883       end;
884     end;
885     if HeadValue['ExtraTip'] <> '' then ShowHintLabel(HeadValue['ExtraTip']);
886   finally
887     HeadValue.Free;
888   end;
889 end;
890
891 procedure TfrmSender.actStartClick(Sender: TObject);
892 begin
893   if Pref.LUID = '' then begin
894     NoLuidError;
895     Exit;
896   end;
897   if not IdSlpp20.Connected then begin
898     FBeginConnectFailCount := 0; // \8e©\93®\8dÄ\90Ú\91±\83J\83E\83\93\83^\83\8a\83Z\83b\83g
899     BeginConnect;
900   end;
901   if Added then begin
902     FAutoAddAfterGetChannel := false;
903     PostCommand(['Command: getChannels']);
904   end;
905 end;
906
907 procedure TfrmSender.actStopExecute(Sender: TObject);
908 begin
909   // \8b­\90§\8dÄ\90Ú\91±\82ð\8ds\82¤
910   IdSlpp20.OnDisconnect := nil;
911   if IdSlpp20.Connected then IdSlpp20.Disconnect;
912   FAutoAddAfterGetChannel := true;
913   BeginConnect;
914   IdSlpp20.OnDisconnect := Slpp20Disconnect;
915 end;
916
917 procedure TfrmSender.FormShow(Sender: TObject);
918 begin
919   if FBooted or Application.Terminated then Exit;
920   //LUID\82ª\8eæ\93¾\82³\82ê\82Ä\82¢\82ê\82Î\91\81\91¬\93o\98^\81B\82»\82¤\82Å\82È\82¯\82ê\82ÎLUID\8eæ\93¾\81B
921   if Pref.LUID <> '' then BeginConnect
922   else mnGetNewIdClick(Self);
923   FAutoAddAfterGetChannel := Pref.AutoStart;
924   FBooted := true;
925   frmLog.Show;
926   frmSurfacePreview.Show;
927   Self.Show;
928   SakuraSeeker.BeginDetect;
929   SakuraSeekerDetectResultChanged(self);
930   if SakuraSeeker.Count = 0 then
931     frmMessageBox.ShowMessage('\83S\81[\83X\83g(SSTP\83T\81[\83o)\82ª1\82Â\82à\8bN\93®\82µ\82Ä\82¢\82Ü\82¹\82ñ\81B'#13#10 +
932       'SSTP Bottle\82ð\97\98\97p\82·\82é\82½\82ß\82É\82Í\81A\83S\81[\83X\83g\82ð\93¯\8e\9e\82É\8bN\93®\82µ\82Ä\82­\82¾\82³\82¢\81B'#13#10 +
933       '\8fÚ\8d×\82Í\83w\83\8b\83v\82ð\82²\97\97\89º\82³\82¢\81B');
934 end;
935
936 procedure TfrmSender.actAboutClick(Sender: TObject);
937 var Str: String;
938 begin
939   Str := VersionString + #13#10 + BottleDisclaimer + #13#10#13#10;
940   Str := Str + Format('Compiler Version: %f', [CompilerVersion]);
941   frmMessageBox.ShowMessage(Str);
942 end;
943
944 procedure TfrmSender.actExitClientExecute(Sender: TObject);
945 begin
946   Close;
947 end;
948
949 procedure TfrmSender.actClearExecute(Sender: TObject);
950 var
951   Script, Default: String;
952 begin
953   Script := StringReplace(GetScriptText, #13#10, '', [rfReplaceAll]);
954   Default := StringReplace(Pref.DefaultScript, '|', '', [rfReplaceAll]);
955   Default := StringReplace(Default, #13#10, '', [rfReplaceAll]);
956
957   if (Pref.AutoClip) and (Length(GetScriptText) > 0) and (Script <> Default) then
958     actSendToLogWindow.Execute
959   else
960     ClearEditor;
961 end;
962
963 procedure TfrmSender.memScriptChange(Sender: TObject);
964 var
965   Script: String;
966   Text: String;
967 begin
968   Script := StringReplace(GetScriptText, #13#10, '', [rfReplaceAll]);
969   Text := Format('%d\83o\83C\83g/%d\95b', [Length(Script), SsPlayTime.PlayTime(Script) div 1000]);
970   StatusBar.Panels[PanelBytes].Text := Text;
971   FScriptModified := true;
972   EditorPreview;
973 end;
974
975 procedure TfrmSender.mnStayOnTopClick(Sender: TObject);
976 begin
977   Pref.StayOnTop := not Pref.StayOnTop;
978   mnStayOnTop.Checked := Pref.StayOnTop;
979   if Pref.StayOnTop then begin
980     FormStyle := fsStayOnTop;
981   end else begin
982     FormStyle := fsNormal;
983   end;
984   Show;
985 end;
986
987 function TfrmSender.GetScriptText: String;
988 begin
989   Result := memScript.Lines.Text;
990 end;
991
992 procedure TfrmSender.mnConstClick(Sender: TObject);
993 var i: integer;
994 begin
995   i := (Sender as TMenuItem).Tag;
996   memScript.SelText := ScriptConstList.GetConstByID(i).ConstText;
997 end;
998
999 procedure TfrmSender.actEditConstExecute(Sender: TObject);
1000 begin
1001   ScriptConstList.LoadFromDir(FConstDir);
1002   try
1003     Application.CreateForm(TfrmConstEditor, frmConstEditor);
1004     frmConstEditor.Execute;
1005     ScriptConstList.Save;
1006   finally
1007     frmConstEditor.Release;
1008   end;
1009   ConstructMenu(false);
1010 end;
1011
1012 procedure TfrmSender.mnTaskBarClick(Sender: TObject);
1013 begin
1014   Application.Minimize;
1015   WindowState := wsNormal;
1016 end;
1017
1018 procedure TfrmSender.FormClose(Sender: TObject; var Action: TCloseAction);
1019 begin
1020   EndConnect;
1021   TaskTray.Registered := false;
1022 end;
1023
1024 procedure TfrmSender.ApplicationEventsMinimize(Sender: TObject);
1025 begin
1026   Visible := false;
1027   Application.ShowMainForm := false;
1028   ShowWindow(Application.Handle, SW_HIDE);
1029 end;
1030
1031 procedure TfrmSender.ApplicationEventsRestore(Sender: TObject);
1032 begin
1033   Application.ShowMainForm := true;
1034   Visible := true;
1035 end;
1036
1037 procedure TfrmSender.mnTaskRestoreClick(Sender: TObject);
1038 begin
1039   Application.Restore;
1040 end;
1041
1042 procedure TfrmSender.TaskTrayDblClick(Seft: TObject; Button: TMouseButton);
1043 begin
1044   Application.Restore;
1045 end;
1046
1047 procedure TfrmSender.FormActivate(Sender: TObject);
1048 begin
1049   memScript.SetFocus;
1050 end;
1051
1052 procedure TfrmSender.mnTaskNewMessageClick(Sender: TObject);
1053 begin
1054   Application.Restore;
1055   actClearExecute(Sender);
1056 end;
1057
1058 procedure TfrmSender.ChangeTaskIcon;
1059 var Ico: TIcon;
1060     IcoNum: integer;
1061 begin
1062   if Added then begin
1063     if Sleeping then IcoNum := IconSleep else IcoNum := IconConnected;
1064   end else begin
1065     if Sleeping then IcoNum := IconSleepDisconnected
1066     else IcoNum := IconDisconnected;
1067   end;
1068   try
1069     Ico := TIcon.Create;
1070     try
1071       imgIcon.GetIcon(IcoNum, Ico);
1072       TaskTray.Icon := Ico;
1073       TaskTray.Registered := true;
1074     finally
1075       Ico.Free;
1076     end;
1077   except
1078     ; // PC\82Ì\95\89\89×\82ª\8d\82\82¢\82Æ4\95b\88È\93à\82É\83^\83X\83N\83g\83\8c\83C\93o\98^\82Å\82«\82¸\81A
1079       // \83V\83F\83\8b\82ª\83n\83\93\83O\82µ\82Ä\82¢\82é\82Æ\94»\92f\82³\82ê\82Ä\97á\8aO\82ª\94­\90\82·\82é\81B
1080       // \82»\82Ì\8fê\8d\87\82Í\83G\83\89\81[\82ð\96³\8e\8b\82·\82é
1081   end;
1082 end;
1083
1084 procedure TfrmSender.SetStatusText(const Value: String);
1085 begin
1086   FStatusText := Value;
1087   StatusBar.Panels[PanelStatus].Text := Value;
1088 end;
1089
1090 procedure TfrmSender.ApplicationEventsHint(Sender: TObject);
1091 var id: integer;
1092 begin
1093   if Length(Application.Hint) > 0 then
1094   begin
1095     StatusBar.Panels[PanelStatus].Text := GetLongHint(Application.Hint);
1096     Application.HintColor := clInfoBk;
1097     if (Application.Hint = SendButtonLongHint)
1098     and (FNowChannel <> '') then
1099     begin
1100       //\91\97\90M\83{\83^\83\93\82Ì\8fê\8d\87\82Í\91¬\8dU\8fo\82·
1101       Application.HintColor := clYellow;
1102       Application.ActivateHint(Mouse.CursorPos);
1103     end;
1104     if IsSurfaceTag(Application.Hint, id) and Pref.SurfacePreviewOnHint then
1105     begin
1106       // \83T\81[\83t\83B\83X\83v\83\8c\83r\83\85\81[
1107       DoSurfacePreview(id, spHint);
1108     end;
1109   end else
1110   begin
1111     StatusBar.Panels[PanelStatus].Text := FStatusText;
1112     frmSurfacePreview.HideAway;
1113   end;
1114 end;
1115
1116 procedure TfrmSender.ConstructMenu(Simple: boolean);
1117 begin
1118   BuildMenu(mnPopConst, Simple);
1119   BuildMenu(mnPopUpConst.Items, Simple);
1120   BuildMenu(ConstBarMenu.Items, Simple);
1121   //ConstMenuBar.Menu := nil;
1122   ConstMenuBar.AutoSize := false;
1123   ConstMenuBar.Width := 1000;
1124   ConstMenuBar.Menu := ConstBarMenu;
1125   ConstMenuBar.AutoSize := true;
1126 end;
1127
1128 procedure TfrmSender.memScriptKeyDown(Sender: TObject; var Key: Word;
1129   Shift: TShiftState);
1130 var Pos: TPoint;
1131     Func: TReturnKeyFunction;
1132 begin
1133   if (Key = VK_RETURN) then begin
1134     if (ssShift in Shift) then
1135       Func := Pref.WhenShiftReturn
1136     else if (ssCtrl in Shift) then
1137       Func := Pref.WhenCtrlReturn
1138     else
1139       Func := Pref.WhenReturn;
1140     case Func of
1141       kfConstText: begin
1142         with tbtnInsertConst do
1143           Pos := tbtnInsertConst.ClientToScreen(Point(0, Height));
1144         mnPopUpConst.Popup(Pos.X, Pos.Y);
1145       end;
1146       kfYenN: begin
1147         memScript.SelText := '\n';
1148         Key := 0;
1149       end;
1150       kfYenNReturn: begin
1151         memScript.SelText := '\n'#13#10;
1152       end;
1153       kfReturn: begin
1154         memScript.SelText := #13#10
1155       end;
1156     end;
1157   end;
1158 end;
1159
1160 procedure TfrmSender.mnShowToolBarClick(Sender: TObject);
1161 begin
1162   mnShowToolBar.Checked := not mnShowToolBar.Checked;
1163   Pref.ShowToolBar := mnShowToolBar.Checked;
1164   UpdateLayout;
1165 end;
1166
1167 procedure TfrmSender.mnShowConstBarClick(Sender: TObject);
1168 begin
1169   mnShowConstBar.Checked := not mnShowConstBar.Checked;
1170   Pref.ShowConstBar := mnShowConstBar.Checked;
1171   UpdateLayout;
1172 end;
1173
1174 procedure TfrmSender.UpdateLayout;
1175 begin
1176   with SakuraScriptFountain do begin
1177     TagColor.Color := Pref.MarkUpColor;
1178     TagErrorColor.Color := Pref.MarkErrorColor;
1179     Scope0Color.Color := Pref.TalkColorH;
1180     Scope1Color.Color := Pref.TalkColorU;
1181     SynchronizedColor.Color := Pref.TalkColorS;
1182   end;
1183   memScript.Ruler.Visible := Pref.ShowRuler;
1184   memScript.Ruler.Color := Pref.TextColor;
1185   memScript.Color := Pref.BgColor;
1186
1187   ToolBar.Visible := Pref.ShowToolBar;
1188   ConstMenuBar.Visible := Pref.ShowConstBar;
1189   ToolBar.Top := 0;
1190   //
1191   with tabChannel do begin
1192     TabPosition := Pref.TabPosition;
1193     case Pref.TabPosition of
1194       tpTop:    Align  := alTop;
1195       tpBottom: Align := alBottom;
1196     end;
1197     TabWidth := Pref.TabWidth;
1198   end;
1199 end;
1200
1201 function TfrmSender.DoTrans(var Script: String;
1202   Options: TScriptTransOptions; out FoundURL: boolean): String;
1203 var UrlCancel, Mark: String;
1204     Url, UrlName: array[0..6] of String;
1205     i, j, u, UrlCount: integer;
1206     LastSurfaceH, LastSurfaceU: integer;
1207     UnyuTalking: boolean;
1208     QuickSection, Synchronize: boolean;
1209     Warnings: TStringList;
1210 begin
1211   UrlCount := 0;
1212   LastSurfaceH := 0;
1213   LastSurfaceU := 10;
1214   UnyuTalking := false;
1215   QuickSection := false;
1216   Synchronize := false;
1217   SsParser.LeaveEscape := true;
1218   SsParser.EscapeInvalidMeta := false;
1219   SsParser.InputString := Script;
1220   Script := '';
1221   Warnings := TStringList.Create;
1222   try
1223     for i := 0 to SsParser.Count-1 do begin
1224       if SsParser[i] = '\t' then begin
1225         if not(toIgnoreTimeCritical in Options) then
1226           Script := Script + '\t';
1227       end else if SsParser[i] = '\e' then begin
1228         Continue;
1229       end else if (SsParser.Match(SsParser[i], '\URL%b') > 0) then begin
1230         if toConvertURL in Options then begin
1231           UrlCount := 0; //\91O\82ÌURL\83^\83O\82Ì\89e\8b¿\82ð\96³\8e\8b\81B
1232           for u := 7 downto 1 do begin
1233             if (SsParser.Match(SsParser[i],
1234                 '\URL%b'+StringReplace(StringOfChar('-', u*2),
1235                 '-', '%b', [rfReplaceAll]))) > 0 then begin
1236               for j := 1 to u do begin
1237                 Url[UrlCount] := SsParser.GetParam(SsParser[i], UrlCount*2+2);
1238                 UrlName[UrlCount] := SsParser.GetParam(SsParser[i], UrlCount*2+3);
1239                 if UrlName[UrlCount] = '' then UrlName[UrlCount] := Url[UrlCount];
1240                 if Pos('http://', Url[UrlCount]) > 0 then Inc(UrlCount);
1241               end;
1242             end;
1243             if UrlCount > 0 then UrlCancel := SsParser.GetParam(SsParser[i], 1);
1244             if UrlCancel = '' then UrlCancel := '\8ds\82©\82È\82¢\81@\81@\81@\81@';
1245           end;
1246           if SsParser.Match(SsParser[i], '\URL%b%b') = 0 then begin //\8aÈ\88Õ\94ÅURL\95Ï\8a·
1247             //\8aÈ\88Õ\8c`\8e®\URL\83^\83O\95Ï\8a·
1248             Url[0] := SsParser.GetParam(SsParser[i], 1);
1249             UrlName[0] := '\8ds\82­\81@\81@\81@\81@\81@\81@';
1250             UrlCancel  := '\8ds\82©\82È\82¢\81@\81@\81@\81@';
1251             if Pos('http://', Url[0]) > 0 then begin
1252               UrlCount := 1;
1253               if not QuickSection then
1254                 Script := Script + '\_q' + Url[0] + '\_q'
1255               else
1256                 Script := Script + Url[0];
1257             end;
1258           end;
1259         end else Script := Script + SsParser[i];
1260       end else begin
1261         Mark := SsParser[i];
1262         if Mark = '\h' then begin
1263           UnyuTalking := false;
1264           if toHUTagTo01Tag in Options then Mark := '\0';
1265           if Synchronize and Pref.WarnScopeChangeInSynchronize then
1266             Warnings.Add('\83V\83\93\83N\83\8d\83i\83C\83Y\83h\83Z\83N\83V\83\87\83\93\92\86\82É\h\82ª\82 \82è\82Ü\82·\81B');
1267         end else if Mark = '\u' then begin
1268           UnyuTalking := true;
1269           if toHUTagTo01Tag in Options then Mark := '\1';
1270           if Synchronize and Pref.WarnScopeChangeInSynchronize then
1271             Warnings.Add('\83V\83\93\83N\83\8d\83i\83C\83Y\83h\83Z\83N\83V\83\87\83\93\92\86\82É\u\82ª\82 \82è\82Ü\82·\81B');
1272         end else if Mark = '\_q' then begin
1273           QuickSection := not QuickSection;
1274         end else if Mark = '\_s' then begin
1275           Synchronize := not Synchronize;
1276         end else if SsParser.Match(Mark, '\s%b') > 0 then begin
1277           if UnyuTalking then begin
1278             LastSurfaceU := StrToIntDef(SsParser.GetParam(Mark, 1),
1279                                         LastSurfaceU);
1280           end else begin
1281             LastSurfaceH := StrToIntDef(SsParser.GetParam(Mark, 1),
1282                                         LastSurfaceH);
1283           end;
1284         end else if SsParser.Match(Mark, '\s%d') > 0 then begin
1285           if UnyuTalking then begin
1286             LastSurfaceU := StrToIntDef(Mark[3], LastSurfaceU);
1287           end else begin
1288             LastSurfaceH := StrToIntDef(Mark[3], LastSurfaceH);
1289           end;
1290         end;
1291         Script := Script + Mark;
1292       end;
1293     end;
1294     if UrlCount > 0 then begin
1295       FoundUrl := true;
1296       Script := Script + '\h\n';
1297       if not (toNoChoice in Options) then begin
1298         for i := 0 to UrlCount-1 do begin
1299           Script := Script + Format('\q%d[%s][%s]',
1300                       [i, SsParser.EscapeParam(Url[i]), UrlName[i]]);
1301         end;
1302         Script := Script + Format('\q%d[#cancel][%s]', [UrlCount, UrlCancel]);
1303         //Script := Script + '\z'; //\8dÅ\90Vphase\82Å\82Í\8dí\8f\9c
1304       end else begin
1305         Script := Script + '\h';
1306         for i := 0 to UrlCount-1 do begin
1307           Script := Script + Format('\n{%s}(%s)', [UrlName[i], Url[i]]);
1308         end;
1309         Script := Script + Format('\n{%s}', [UrlCancel]);
1310       end;
1311     end else
1312       FoundUrl := false;
1313     //\83X\83N\83\8a\83v\83g\82Ì\8dÅ\8cã\82É\83E\83F\83C\83g\91}\93ü
1314     if toWaitScriptEnd in Options then begin
1315       i := Pref.WaitScriptEnd;
1316       while i > 0 do begin
1317         if i > 9 then begin
1318           Script := Script + '\w9';
1319           Dec(i, 9);
1320         end else begin
1321           Script := Script + '\w' + IntToStr(i);
1322           i := 0;
1323         end;
1324       end;
1325     end;
1326
1327     Script := Script + '\e';
1328     RegExp.Subst('s/\r\n//gk', Script);
1329
1330     //\83^\83O\83`\83F\83b\83N\8aÖ\98A
1331     for i := 0 to SsParser.Count-1 do begin
1332       if SsParser.MarkUpType[i] = mtTagErr then begin
1333         Result := '"' + SsParser[i] + '"'#13#10 +
1334                   '\82Í\81ASSTP Bottle\82Å\94F\82ß\82ç\82ê\82È\82¢\82©\81A\94F\8e¯\82Å\82«\82È\82¢\83^\83O\82Å\82·\81B';
1335         Exit;
1336       end;
1337     end;
1338     if (SsParser[0] <> '\t') and Pref.WarnYenTNotExist then begin
1339       Warnings.Add('\83X\83N\83\8a\83v\83g\82ª\t\82©\82ç\8en\82Ü\82Á\82Ä\82¢\82Ü\82¹\82ñ\81B');
1340     end;
1341
1342     //\83`\83F\83b\83N
1343     if (Warnings.Count > 0) and (toWarnCheck in Options) then begin
1344       if MessageDlg(Warnings.Text + #13#10 + '\91\97\90M\82µ\82Ü\82·\82©?', mtWarning,
1345                     mbOkCancel, 0) = mrCancel then
1346         Result := Warnings.Text;
1347     end;
1348   finally
1349     Warnings.Free;
1350   end;
1351 end;
1352
1353 function TfrmSender.DoTrans(var Script: String;
1354   Options: TScriptTransOptions): String;
1355 var dum: boolean;
1356 begin
1357   Result := DoTrans(Script, Options, dum);
1358 end;
1359
1360 procedure TfrmSender.mnGoToHPClick(Sender: TObject);
1361 begin
1362   ShellExecute(Handle, 'open', PChar(Pref.HomePage), nil, nil, SW_SHOW);
1363 end;
1364
1365 procedure TfrmSender.ShowHintLabel(const Mes: String; Col: TColor);
1366 begin
1367   lblMessage.Caption := Mes;
1368   lblMessage.Font.Color := Col;
1369   lblMessage.Visible := true;
1370   LabelTimer.Enabled := false;
1371   LabelTimer.Enabled := true;
1372 end;
1373
1374 procedure TfrmSender.LabelTimerTimer(Sender: TObject);
1375 begin
1376   LabelTimer.Enabled := false;
1377   lblmessage.Visible := false;
1378 end;
1379
1380 procedure TfrmSender.actCopyAllExecute(Sender: TObject);
1381 var Str: String;
1382     Clip: TClipBoard;
1383 begin
1384   Str := memScript.Lines.Text;
1385   Clip := ClipBoard();
1386   Clip.SetTextBuf(PChar(Str));
1387 end;
1388
1389 procedure TfrmSender.actCopyAllNoReturnExecute(Sender: TObject);
1390 var Str: String;
1391     Clip: TClipBoard;
1392 begin
1393   Str := memScript.Lines.Text;
1394   RegExp.Subst('s/\r\n//gk', Str);
1395   Clip := ClipBoard();
1396   Clip.SetTextBuf(PChar(Str));
1397 end;
1398
1399 procedure TfrmSender.Slpp20SlppEvent(Sender: TObject; EventType: TIdSlppEventType;
1400   const Param: String);
1401 var HeadValue: THeadValue;
1402 begin
1403   HeadValue := THeadValue.Create(Param);
1404   try
1405     case EventType of
1406       etScript, etForceBroadcast, etUnicast: begin
1407         //\83\81\83b\83Z\81[\83W\8eó\90M
1408         DispatchBottle(EventType, HeadValue);
1409       end;
1410       etMemberCount: begin
1411         StatusBar.Panels[PanelMembers].Text := HeadValue['Num'] + '\90l'
1412       end;
1413       etChannelCount: begin
1414         try
1415           ChannelList.Channel[HeadValue['Channel']].Members := StrToInt(HeadValue['Num']);
1416         except
1417         end;
1418       end;
1419       etConnectOk: begin
1420         ShowHintLabel('SSTP Bottle\83T\81[\83o\82Æ\92Ê\90M\8am\97§\81B');
1421         Added := true;
1422         FBeginConnectFailCount := 0;
1423         //\83`\83\83\83\93\83l\83\8b\8e©\93®\93o\98^
1424         if not Connecting then
1425           PostCommand(['Command: getChannels']);
1426         SakuraSeeker.BeginDetect;
1427       end;
1428       etChannelList: begin
1429         UpdateJoinChannelList(HeadValue);
1430         // \8dÅ\8cã\82É\8eQ\89Á\82µ\82Ä\82¢\82½\83`\83\83\83\93\83l\83\8b\82ð\8bL\98^\82·\82é
1431         if JoinChannelsBackup = nil then JoinChannelsBackup := TStringList.Create;
1432         JoinChannelsBackup.Assign(JoinChannels);
1433       end;
1434       etCloseChannel: begin
1435         with JoinChannels do
1436           if IndexOf(HeadValue['Channel']) >= 0 then
1437             Delete(IndexOf(HeadValue['Channel']));
1438         with tabChannel do begin
1439           if Tabs.IndexOf(HeadValue['Channel']) >= 0 then
1440             Tabs.Delete(Tabs.IndexOf(HeadValue['Channel']));
1441           if Tabs.Count > 0 then TabIndex := 0 else TabIndex := -1;
1442           tabChannelChange(self);
1443         end;
1444         ShowHintLabel(HeadValue['Channel'] + '\83`\83\83\83\93\83l\83\8b\82Í\94p\8e~\82³\82ê\82Ü\82µ\82½',
1445                       WarningColor);
1446         frmLog.AddCurrentSystemLog('SYSTEM', HeadValue['Channel'] + '\83`\83\83\83\93\83l\83\8b\82Í\94p\8e~\82³\82ê\82Ü\82µ\82½');
1447         frmMessageBox.ShowMessage(HeadValue['Channel'] + '\83`\83\83\83\93\83l\83\8b\82Í\94p\8e~\82³\82ê\82Ü\82µ\82½');
1448       end;
1449       etForceBroadcastInformation: begin
1450         if HeadValue['Type'] = 'Vote' then begin
1451           frmLog.VoteLog(HeadValue['MID'], StrToIntDef(HeadValue['Num'], 0));
1452         end else if HeadValue['Type'] = 'Agree' then begin
1453           frmLog.AgreeLog(HeadValue['MID'], StrToIntDef(HeadValue['Num'], 0));
1454         end;
1455       end;
1456     end;
1457   finally
1458     HeadValue.Free;
1459   end;
1460 end;
1461
1462 procedure TfrmSender.BottleSstpResendCountChange(Sender: TObject);
1463 begin
1464   StatusBar.Panels[PanelCount].Text := IntToStr(FBottleSstp.CueCount) + '\8c\8f';
1465   try
1466     TaskTray.TipString := 'SSTP Bottle Client (' +
1467                           IntToStr(FBottleSstp.CueCount) + '\8c\8f)';
1468   except
1469     ; // \83^\83X\83N\83g\83\8c\83C\93o\98^\8e¸\94s\82ð\96³\8e\8b\82·\82é
1470   end;
1471   actClearBottles.Enabled := (FBottleSstp.CueCount > 0);
1472 end;
1473
1474 procedure TfrmSender.actSettingExecute(Sender: TObject);
1475 begin
1476   Application.CreateForm(TfrmSetting, frmSetting);
1477   try
1478     frmSetting.Execute;
1479     Pref.SaveSettings;
1480     SaveChainRuleList;
1481   finally
1482     frmSetting.Release;
1483     frmSetting := nil;
1484   end;
1485   //
1486   UpdateLayout;
1487   tabChannel.Repaint;
1488   frmLog.UpdateWindow;
1489 end;
1490
1491 procedure TfrmSender.memScriptKeyPress(Sender: TObject; var Key: Char);
1492 begin
1493   if (Key = #13) or (Key = #10) then Key := Char(0);
1494 end;
1495
1496 procedure TfrmSender.Slpp20Disconnect(Sender: TObject);
1497 begin
1498   Added := false;
1499   UpdateJoinChannelList(nil);
1500   frmLog.AddCurrentSystemLog('SYSTEM', '\83T\81[\83o\82©\82ç\90Ø\92f\82³\82ê\82Ü\82µ\82½');
1501   if not Application.Terminated then RetryBeginConnect;
1502 end;
1503
1504 procedure TfrmSender.SetSleeping(const Value: boolean);
1505 begin
1506   FSleeping := Value;
1507   FBottleSstp.ResendSleep := Value;
1508   ChangeTaskIcon;
1509 end;
1510
1511 procedure TfrmSender.actClearBottlesExecute(Sender: TObject);
1512 var Re: integer;
1513 begin
1514   Re := MessageDlg(Format('\96¢\94z\91\97\82Ì%d\8c\8f\82ÌBottle\82ð\91S\95\94\83N\83\8a\83A\82µ\82Ü\82·', [FBottleSstp.CueCount]),
1515                    mtWarning, mbOkCancel, 0);
1516   if Re = mrOk then begin
1517     FBottleSstp.Clear;
1518     frmLog.AllBottleOpened;
1519     frmLog.UpdateWindow;
1520   end;
1521 end;
1522
1523 procedure TfrmSender.SakuraSeekerDetectResultChanged(Sender: TObject);
1524 begin
1525   UpdateIfGhostBox; // \83h\83\8d\83b\83v\83_\83E\83\93\82Ì\92\86\90g\82ð\8f\91\82«\8a·\82¦\82é
1526 end;
1527
1528 procedure TfrmSender.UpdateChannelInfo(Dat: THeadValue);
1529 var i: integer;
1530     Ch: TChannelListItem;
1531 begin
1532   ChannelList.Clear;
1533   for i := 1 to Dat.IntData['Count'] do begin
1534     Ch := TChannelListItem.Create;
1535     Ch.Name    := Dat[Format('CH%d_name', [i])];
1536     Ch.Ghost   := Dat[Format('CH%d_ghost', [i])];
1537     Ch.Info    := Dat[Format('CH%d_info', [i])];
1538     Ch.NoPost  := Dat[Format('CH%d_nopost', [i])] = '1';
1539     Ch.Members := Dat.IntData[Format('CH%d_count', [i])];
1540     Ch.WarnPost:= Dat[Format('CH%d_warnpost', [i])] = '1';
1541     ChannelList.Add(Ch);
1542   end;
1543   UpdateLayout;
1544 end;
1545
1546 procedure TfrmSender.mnGetNewIdClick(Sender: TObject);
1547 begin
1548   PostCommand(['Command: getNewId', 'Agent: ' + VersionString]);
1549 end;
1550
1551 procedure TfrmSender.NoLuidError;
1552 begin
1553   Beep;
1554   ShowMessage('SSTP Bottle ID\82Ì\8eæ\93¾\82ª\82Ü\82¾\8a®\97¹\82µ\82Ä\82¢\82Ü\82¹\82ñ\81B'#13#10+
1555               '\83w\83\8b\83v\83\81\83j\83\85\81[\82Ì[LUID\8eæ\93¾]\82©\82çID\82ð\8eæ\93¾\82µ\82Ä\82­\82¾\82³\82¢\81B'#13#10+
1556               '\82±\82Ì\91\80\8dì\82ÍClient\8f\89\89ñ\8bN\93®\8e\9e\82É1\89ñ\82¾\82¯\95K\97v\82Å\82·\81B');
1557 end;
1558
1559 procedure TfrmSender.tabChannelChange(Sender: TObject);
1560 begin
1561   if tabChannel.TabIndex >= 0 then begin
1562     FNowChannel := tabChannel.Tabs[tabChannel.TabIndex];
1563     actSend.Hint := Format('\81u%s\81v\82É\91\97\90M|%s', [FNowChannel, SendButtonLongHint]);
1564   end else begin
1565     FNowChannel := '';
1566     actSend.Hint := '';
1567   end;
1568   tabChannel.Repaint; //\82±\82ê\82ª\82È\82¢\82Æ\90F\82ª\95Ï\82í\82ç\82È\82¢\82±\82Æ\82ª\82 \82é
1569   ConstructMenu(true);
1570 end;
1571
1572 procedure TfrmSender.actPrevChannelExecute(Sender: TObject);
1573 begin
1574   with tabChannel do begin
1575     if Tabs.Count = 0 then Exit;
1576     if TabIndex=0 then TabIndex := Tabs.Count-1
1577     else TabIndex := TabIndex-1;
1578   end;
1579   tabChannelChange(Self);
1580 end;
1581
1582 procedure TfrmSender.actNextChannelExecute(Sender: TObject);
1583 begin
1584   with tabChannel do begin
1585     if Tabs.Count = 0 then Exit;
1586     if TabIndex=Tabs.Count-1 then TabIndex := 0
1587     else TabIndex := TabIndex+1;
1588   end;
1589   tabChannelChange(Self);
1590 end;
1591
1592 procedure TfrmSender.UpdateJoinChannelList(Dat: THeadValue);
1593 var i: integer;
1594     nodat: boolean;
1595 begin
1596   nodat := Dat = nil; //nil\82È\82ç\83`\83\83\83\93\83l\83\8b\91S\89ð\8f\9c
1597   if nodat then Dat := THeadValue.Create('');
1598   JoinChannels.Clear;
1599   for i := 0 to Dat.Count-1 do
1600     if Dat.KeyAt[i] = 'Entry' then begin
1601       if RegExp.Match('m/^(.+?) \((\d+?)\)$/', Dat.ValueAt[i]) then
1602         JoinChannels.Add(RegExp[1]);
1603     end;
1604   with tabChannel do begin
1605     OnChange := nil;
1606     JoinChannels.Sort;
1607     Tabs.BeginUpdate;
1608     Tabs.Clear;
1609     for i := 0 to JoinChannels.Count-1 do begin
1610       //\8eó\90M\90ê\97p\83`\83\83\83\93\83l\83\8b\82Í\95\\8e¦\82µ\82È\82¢
1611       if not ChannelList.Channel[JoinChannels[i]].NoPost then
1612         Tabs.Add(JoinChannels[i]);
1613     end;
1614     Tabs.EndUpdate;
1615     // \8c³\82©\82ç\83`\83\83\83\93\83l\83\8b\82É\8eQ\89Á\82µ\82Ä\82¢\82½\8fê\8d\87\82Í
1616     // \91I\91ð\82³\82ê\82Ä\82¢\82½\83`\83\83\83\93\83l\83\8b\82ª\95Ï\82í\82ç\82È\82¢\82æ\82¤\82É\82·\82é(\83^\83u\82ª\82¸\82ê\82È\82¢\8f\88\97\9d)
1617     TabIndex := 0;
1618     for i := 0 to Tabs.Count-1 do
1619       if Tabs[i] = FNowChannel then TabIndex := i;
1620     if Tabs.Count > 0 then begin
1621       FNowChannel := Tabs[TabIndex];
1622       actSend.Hint := Format('\81u%s\81v\82É\91\97\90M|%s', [FNowChannel, SendButtonLongHint]);
1623     end else begin
1624       FNowChannel := '';
1625       actSend.Hint := Format('\91\97\90M|%s', [SendButtonLongHint]);
1626     end;
1627     Visible := Tabs.Count > 0;
1628     if Tabs.Count > 1 then begin
1629       actNextChannel.Enabled := true;
1630       actPrevChannel.Enabled := true;
1631     end else begin
1632       actNextChannel.Enabled := false;
1633       actPrevChannel.Enabled := false;
1634     end;
1635     OnChange := tabChannelChange;
1636   end;
1637   if nodat then Dat.Free;
1638   if JoinChannels.Count = 0 then begin
1639     Self.Caption := FOriginalCaption + ' - \83`\83\83\83\93\83l\83\8b\82É\8eQ\89Á\82µ\82Ä\82¢\82Ü\82¹\82ñ';
1640     actSend.Enabled := false;
1641   end else begin
1642     Self.Caption := FOriginalCaption;
1643     actSend.Enabled := true;
1644   end;
1645 end;
1646
1647 procedure TfrmSender.cbxTargetGhostDropDown(Sender: TObject);
1648 begin
1649   SakuraSeeker.BeginDetect;
1650   UpdateIfGhostBox;
1651 end;
1652
1653 procedure TfrmSender.actShowLogExecute(Sender: TObject);
1654 begin
1655   frmLog.Show;
1656   if frmLog.WindowState = wsMinimized then frmLog.WindowState := wsNormal;
1657 end;
1658
1659 procedure TfrmSender.actSleepExecute(Sender: TObject);
1660 begin
1661   if actSleep.Checked then begin
1662     actSleep.Checked := false;
1663     ShowHintLabel('\83X\83\8a\81[\83v\82ð\89ð\8f\9c\82µ\82Ü\82µ\82½');
1664   end else begin
1665     actSleep.Checked := true;
1666     ShowHintLabel('\83X\83\8a\81[\83v\82ð\90Ý\92è\82µ\82Ü\82µ\82½');
1667   end;
1668   Sleeping := actSleep.Checked;
1669   ChangeTaskIcon;
1670 end;
1671
1672
1673 procedure TfrmSender.DispatchBottle(EventType: TIdSlppEventType;
1674   Dat: THeadValue);
1675 var Opt: TSstpSendOptions;
1676     Event: TBottleChainBottleEvent;
1677     Script, Sender, Ghost, Channel, ErrorMes: String;
1678     BreakFlag, NoDispatch: boolean;
1679     Sound, LogName: String;
1680     i, j, k, SkipCount: integer;
1681     Rule: TBottleChainRule;
1682     Action: TBottleChainAction;
1683     LogNameList: TStringList;
1684     CueItem: TLogItem;
1685     ReplaceHash: THeadValue; 
1686 begin
1687   Opt := [];
1688   if Pref.NoTranslate then Opt := Opt + [soNoTranslate];
1689   if Pref.NoDescript  then Opt := Opt + [soNoDescript];
1690   Channel := Dat['Channel'];
1691   case EventType of
1692     etScript: Sender := Channel;
1693     etForceBroadcast: Sender := '\81y\82¨\92m\82ç\82¹\81z';
1694     etUnicast: Sender := Dat['SenderUID'];
1695   end;
1696
1697   //\96Ú\95W\83S\81[\83X\83g(\83I\81[\83o\81[\83\89\83C\83h\88È\91O)\8c\88\92è
1698   if Dat['IfGhost'] <> '' then begin
1699     Ghost := Dat['IfGhost'];
1700   end else begin
1701     if ChannelList.Channel[Channel] <> nil then
1702       Ghost := ChannelList.Channel[Channel].Ghost;
1703   end;
1704   Dat['TargetGhost'] := Ghost;
1705
1706   // \83\81\83^\95\8e\9a\8f\80\94õ
1707   ReplaceHash := THeadValue.Create;
1708   ReplaceHash['%channel%'] := SafeFileName(Dat['Channel']);
1709   ReplaceHash['%ghost%'] := SafeFileName(Dat['IfGhost']);
1710   ReplaceHash['%date%'] := FormatDateTime('yy-mm-dd', Now());
1711   ReplaceHash['%year%'] := FormatDateTime('yyyy', Now());
1712   ReplaceHash['%yy%'] := FormatDateTime('yy', Now());
1713   ReplaceHash['%month%'] := FormatDateTime('mm', Now());
1714   ReplaceHash['%day%'] := FormatDateTime('dd', Now());
1715   ReplaceHash['%hour%'] := FormatDateTime('hh', Now());
1716   ReplaceHash['%minute%'] := FormatDateTime('nn', Now());
1717
1718   Event := TBottleChainBottleEvent.Create;
1719   try
1720     Event.Data := Dat;
1721     if EventType = etScript then Event.LogType := ltBottle
1722     else Event.LogType := ltSystemLog;
1723
1724     //\83X\83N\83\8a\83v\83g\95Ï\8a·
1725     Script := ScriptTransForSSTP(Dat['Script'], ErrorMes);
1726     if ErrorMes <> '' then begin
1727       frmLog.AddCurrentSystemLog('SYSTEM', '\96â\91è\82Ì\82 \82é\89Â\94\\90«\82Ì\82 \82é\83X\83N\83\8a\83v\83g\82ª\93Í\82¢\82½\82½\82ß\81A'+
1728                     '\94z\91\97\82³\82ê\82Ü\82¹\82ñ\82Å\82µ\82½\81@\81c '+Dat['Script']);
1729       Exit;
1730     end;
1731
1732     BreakFlag := false;
1733     NoDispatch := false;
1734     Sound := '';
1735     LogNameList := TStringList.Create;
1736     SkipCount := 0;
1737     try
1738       for i := 0 to BottleChainRuleList.Count-1 do begin
1739         if SkipCount > 0 then begin
1740           Dec(SkipCount);
1741           Continue;
1742         end;
1743         Rule := BottleChainRuleList[i];
1744         if not Rule.Enabled then Continue;
1745         if not Rule.Check(Event) then Continue;
1746         for j := 0 to Rule.Actions.Count-1 do begin
1747           Action := (Rule.Actions[j] as TBottleChainAction);
1748           if Action is TBottleChainAbortRuleAction then
1749             BreakFlag := true;
1750           if Action is TBottleChainSkipRuleAction then
1751             SkipCount := (Action as TBottleChainSkipRuleAction).SkipCount;
1752           if (Action is TBottleChainSoundAction) and (Sound = '') then
1753           begin
1754             Sound := (Action as TBottleChainSoundAction).SoundFile;
1755             Sound := StringReplaceEx(Sound, ReplaceHash);
1756           end;
1757           if Action is TBottleChainNoDispatchAction then
1758             NoDispatch := true;
1759           if Action is TBottleChainLogAction then
1760           begin
1761             for k := 0 to (Action as TBottleChainLogAction).LogNames.Count-1 do begin
1762               LogName := (Action as TBottleChainLogAction).LogNames[k];
1763               LogName := StringReplaceEx(LogName, ReplaceHash);
1764               LogNameList.Add(LogName);
1765             end;
1766           end;
1767           if Action is TBottleChainOverrideGhostAction then
1768           begin
1769             Dat['TargetGhost'] := (Action as TBottleChainOverrideGhostAction).TargetGhost;
1770           end;
1771           if Action is TBottleChainQuitAction then
1772             Application.Terminate;
1773           if Action is TBottleChainSaveTextLogAction then
1774             AppendTextLog(StringReplaceEx((Action as TBottleChainSaveTextLogAction).FileName, ReplaceHash),
1775               Format('%s,%s,%s,%s', [Dat['Channel'], Dat['IfGhost'],
1776                 FormatDateTime('yy/mm/dd hh:nn:ss', Now), Dat['Script']]));
1777           if Action is TBottleChainSaveXMLLogAction then
1778             AppendXMLLog(StringReplaceEx((Action as TBottleChainSaveXMLLogAction).FileName, ReplaceHash),
1779               Dat);
1780           if Action is TBottleChainSurfaceReplaceAction then
1781             Script := ReplaceSurface(Script, (Action as TBottleChainSurfaceReplaceAction).Params);
1782         end;
1783         if BreakFlag then Break;
1784       end;
1785
1786       if Dat['Script'] <> '' then begin
1787         for i := 0 to LogNameList.Count-1 do
1788           frmLog.AddCurrentScriptLog(LogNameList[i], Dat['Script'], Sender, Dat['MID'], Dat['IfGhost']);
1789         if NoDispatch then begin
1790           frmLog.SetBottleState(Dat['MID'], lsOpened);
1791         end else begin
1792           Ghost := Dat['TargetGhost']; // \83I\81[\83o\81[\83\89\83C\83h\82³\82ê\82Ä\82¢\82é\89Â\94\\90«\82ª\82 \82é
1793           CueItem := TLogItem.Create(ltBottle, Dat['MID'], Dat['Channel'],
1794             Script, Ghost, Now());
1795           try
1796             FBottleSstp.Push(CueItem);
1797           except
1798             CueItem.Free;
1799           end;
1800         end;
1801       end;
1802
1803       if Dat['DialogMessage'] <> '' then begin
1804         Beep;
1805         frmMessageBox.ShowMessage(
1806           DateTimeToStr(Now) + #13#10 +
1807           'SSTP Bottle\83T\81[\83o\82©\82ç\82¨\92m\82ç\82¹'#13#10+Dat['DialogMessage']);
1808         for i := 0 to LogNameList.Count-1 do
1809           frmLog.AddCurrentSystemLog(LogNameList[i], Dat['DialogMessage']);
1810       end;
1811
1812       //\89¹\82Ì\8dÄ\90
1813       if (Sound <> '') then PlaySound(Sound);
1814     finally
1815       LogNameList.Free;
1816     end;
1817   finally
1818     Event.Free;
1819     ReplaceHash.Free;
1820   end;
1821 end;
1822
1823 procedure TfrmSender.YenETrans;
1824 var St, Le, i: integer;
1825     Orig, Text: String;
1826 begin
1827   St := memScript.SelStart;
1828   Le := memScript.SelLength;
1829   Orig := GetScriptText;
1830   RegExp.Subst('s/(\r\n)+$//kg', Orig);
1831
1832   with SsParser do begin
1833     LeaveEscape := true;
1834     EscapeInvalidMeta := false;
1835     InputString := Orig;
1836   end;
1837   for i := 0 to SsParser.Count-1 do begin
1838     if SsParser[i] <> '\e' then Text := Text + SsParser[i];
1839   end;
1840
1841   Text := Text + '\e';
1842
1843   if Orig <> Text then memScript.Lines.Text := Text;
1844   SsParser.InputString := Text;
1845
1846   RegExp.Subst('s/\r\n//kg', Text);
1847   memScript.SetFocus;
1848   memScript.SelStart := St;
1849   memScript.SelLength := Le;
1850 end;
1851
1852 procedure TfrmSender.PostCommand(const Command: array of String);
1853 var PostStr: TStringList;
1854     i: integer;
1855 begin
1856   PostStr := nil;
1857   try
1858     PostStr := TStringList.Create;
1859     for i := Low(Command) to High(Command) do begin
1860       PostStr.Add(Command[i]);
1861     end;
1862     PostCommand(PostStr);
1863   finally
1864     PostStr.Free;
1865   end;
1866 end;
1867
1868 procedure TfrmSender.PostCommand(Command: TStrings);
1869 var PostStr: String;
1870 begin
1871   Connecting := true;
1872   PostStr := Command.Text;
1873   PostStr := ParamsEncode(PostStr);
1874   try
1875     FHttp := THTTPDownloadThread.Create(Pref.BottleServer, Pref.CgiName, PostStr);
1876     if Pref.UseHttpProxy then begin
1877       FHttp.ProxyServer := Pref.ProxyAddress;
1878       FHttp.ProxyPort   := Pref.ProxyPort;
1879     end;
1880     FHttp.OnSuccess := HttpSuccess;
1881     FHttp.OnConnectionFailed := HttpFailure;
1882     FHttp.FreeOnTerminate := true; // \8f\9f\8eè\82É\8e©\95ª\82ÅFree\82µ\82Ä\82­\82¾\82³\82¢
1883     FHTTP.Resume;
1884   except
1885     on EHeapException do begin
1886       Connecting := false;
1887       FHttp.Free;
1888     end;
1889   end;
1890 end;
1891
1892 procedure TfrmSender.actVoteMessageExecute(Sender: TObject);
1893 var Log: TLogItem;
1894 begin
1895   if frmLog.lvwLog.Selected = nil then Exit;
1896   Log := frmLog.SelectedBottleLog[frmLog.lvwLog.Selected.Index] as TLogItem;
1897   if Log = nil then Exit;
1898   if Log.LogType <> ltBottle then Exit;
1899   PostCommand([
1900     'Command: voteMessage',
1901     'VoteType: Vote',
1902     'LUID: ' + Pref.LUID,
1903     'MID: ' + Log.MID
1904   ]);
1905 end;
1906
1907
1908 procedure TfrmSender.actAgreeMessageExecute(Sender: TObject);
1909 var Log: TLogItem;
1910 begin
1911   if frmLog.lvwLog.Selected = nil then Exit;
1912   Log := frmLog.SelectedBottleLog[frmLog.lvwLog.Selected.Index] as TLogItem;
1913   if Log = nil then Exit;
1914   if Log.LogType <> ltBottle then Exit;
1915   PostCommand([
1916     'Command: voteMessage',
1917     'VoteType: Agree',
1918     'LUID: ' + Pref.LUID,
1919     'MID: ' + Log.MID
1920   ]);
1921 end;
1922
1923
1924 function TfrmSender.GhostNameToSetName(const Ghost: String): String;
1925 begin
1926   if SakuraSeeker.ProcessByName[Ghost] <> nil then
1927     Result := SakuraSeeker.ProcessByName[Ghost].SetName
1928   else
1929     Result := '';
1930 end;
1931
1932 procedure TfrmSender.tabChannelContextPopup(Sender: TObject;
1933   MousePos: TPoint; var Handled: Boolean);
1934 var Ch: String;
1935 begin
1936   with tabChannel do begin
1937     Tag := IndexOfTabAt(MousePos.X, MousePos.Y);
1938     if Tag < 0 then Handled := true;
1939     Ch := Tabs[Tag];
1940   end;
1941 end;
1942
1943 procedure TfrmSender.PostSetChannel(Channels: TStrings);
1944 var PostStr: TStringList;
1945     i: integer;
1946 begin
1947   PostStr := TStringList.Create;
1948   try
1949     with PostStr do begin
1950       Add('Command: setChannels');
1951       Add('Agent: ' + VersionString);
1952       Add('LUID: ' + Pref.LUID);
1953       if Channels <> nil then
1954         for i := 0 to Channels.Count-1 do begin
1955           Add(Format('Ch%d: %s'#13#10, [i+1, Channels[i]]));
1956         end;
1957     end;
1958     PostCommand(PostStr);
1959   finally
1960     PostStr.Free;
1961   end;
1962 end;
1963
1964 procedure TfrmSender.mnLeaveThisChannelClick(Sender: TObject);
1965 var Ch: String;
1966     Chs: TStringList;
1967 begin
1968   // \8ew\92è\82µ\82½\83`\83\83\83\93\83l\83\8b\82©\82ç\94²\82¯\82é
1969   with tabChannel do
1970     Ch := Tabs[Tag]; // \94²\82¯\82½\82¢\83`\83\83\83\93\83l\83\8b\96¼
1971   Chs := TStringList.Create;
1972
1973   // \8c»\8dÝ\8eQ\89Á\92\86\82Ì\83`\83\83\83\93\83l\83\8b\82©\82ç\81A\94²\82¯\82½\82¢\83`\83\83\83\93\83l\83\8b\82ð
1974   // \8aO\82µ\82½\83\8a\83X\83g\82Å\81A\90V\82½\82É\83`\83\83\83\93\83l\83\8b\8eQ\89Á\83R\83}\83\93\83h\82ð\91\97\82é
1975   try
1976     Chs.Assign(JoinChannels);
1977     while Chs.IndexOf(Ch) >= 0 do
1978       Chs.Delete(Chs.IndexOf(Ch));
1979     PostSetChannel(Chs);
1980   finally
1981     Chs.Free;
1982   end;
1983 end;
1984
1985 procedure TfrmSender.mnGotoVoteClick(Sender: TObject);
1986 begin
1987   ShellExecute(Handle, 'open', PChar(Pref.VotePage), nil, nil, SW_SHOW);
1988 end;
1989
1990 procedure TfrmSender.tabChannelMouseMove(Sender: TObject;
1991   Shift: TShiftState; X, Y: Integer);
1992 var Index: integer;
1993     Ch: String;
1994 begin
1995   with tabChannel do begin
1996     Index := IndexOfTabAt(X, Y);
1997     Ch := Tabs[Index];
1998     Hint := Ch + ': ' + IntToStr(ChannelList.Channel[Ch].Members) + '\90l';
1999   end;
2000 end;
2001
2002 procedure TfrmSender.mnGoToHelpClick(Sender: TObject);
2003 begin
2004   ShellExecute(Handle, 'open', PChar(Pref.HelpPage), nil, nil, SW_SHOW);
2005 end;
2006
2007 procedure TfrmSender.tabChannelMouseDown(Sender: TObject;
2008   Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
2009 var Index: integer;
2010 begin
2011   with tabChannel do begin
2012     Index := IndexOfTabAt(X, Y);
2013     if Index = -1 then Exit; //\83^\83u\82ª\82È\82¢\82Ì\82Å\83h\83\89\83b\83O\82Å\82«\82È\82¢
2014     if Button = mbLeft then begin
2015       FDragTabIndex := Index; //\83h\83\89\83b\83O\82·\82é\83^\83u\82Ì\83C\83\93\83f\83b\83N\83X\82ð\95Û\91
2016       BeginDrag(False);
2017       FDragTabDest := -1;     //\83h\83\89\83b\83O\98g\90ü\95`\89æ\83t\83\89\83O\83N\83\8a\83A\82Ì\82½\82ß
2018     end;
2019   end;
2020 end;
2021
2022 procedure TfrmSender.tabChannelDragOver(Sender, Source: TObject; X,
2023   Y: Integer; State: TDragState; var Accept: Boolean);
2024 var TargetRect: TRect;
2025     OldDest: integer;
2026 begin
2027   Accept := Source = tabChannel;
2028   if not Accept then Exit;
2029   with tabChannel do begin
2030     OldDest := FDragTabDest;
2031     FDragTabDest := IndexOfTabAt(X, Y);
2032     if FDragTabDest = -1 then begin
2033       Accept := false; //\82±\82Ì\8fê\8d\87\82Í\83h\83\8d\83b\83v\82ð\94F\82ß\82È\82¢
2034       Exit;
2035     end;
2036     with Canvas do begin
2037       Pen.Mode := pmNot;
2038       Pen.Width := 3;
2039     end;
2040     if (OldDest <> FDragTabDest) and (OldDest >= 0) then begin
2041       //\88È\91O\82Ì\98g\90ü\8fÁ\8b\8e
2042       TargetRect := TabRect(OldDest);
2043       with Canvas do begin
2044         Brush.Style := bsClear;
2045         Rectangle(TargetRect.Left, TargetRect.Top,
2046                   TargetRect.Right, TargetRect.Bottom);
2047       end;
2048     end;
2049     if (OldDest <> FDragTabDest) then begin
2050       //\90V\82µ\82¢\98g\90ü\95`\89æ
2051       TargetRect := TabRect(FDragTabDest);
2052       with Canvas do begin
2053         Brush.Style := bsClear;
2054         Rectangle(TargetRect.Left, TargetRect.Top,
2055                   TargetRect.Right, TargetRect.Bottom);
2056       end;
2057     end;
2058   end;
2059 end;
2060
2061 procedure TfrmSender.tabChannelDragDrop(Sender, Source: TObject; X,
2062   Y: Integer);
2063 var DestIndex: integer;
2064 begin
2065   with tabChannel do begin
2066     DestIndex := IndexOfTabAt(X, Y);
2067     Tabs.Move(FDragTabIndex, DestIndex);
2068   end;
2069 end;
2070
2071 procedure TfrmSender.tabChannelEndDrag(Sender, Target: TObject; X,
2072   Y: Integer);
2073 begin
2074   //\8b­\90§\93I\82É\83^\83u\82ð\8dÄ\95`\89æ\82³\82¹\82é\81B\98g\90ü\8fÁ\82µ\91Î\8dô
2075   tabChannel.Tabs.BeginUpdate;
2076   tabChannel.Tabs.EndUpdate;
2077 end;
2078
2079 procedure TfrmSender.cbxTargetGhostDrawItem(Control: TWinControl;
2080   Index: Integer; Rect: TRect; State: TOwnerDrawState);
2081 var AlignRight: boolean;
2082     w: integer;
2083 begin
2084   //\83S\81[\83X\83g\91I\91ð\83{\83b\83N\83X\82Ì\83I\81[\83i\81[\83h\83\8d\81[
2085   with cbxTargetGhost do begin
2086     AlignRight := false;
2087     if Pref.HideGhosts and not FTargetGhostExpand and
2088        (Index = Items.Count-1) and (Index > 0) then
2089     begin
2090       // \81u\82·\82×\82Ä\95\\8e¦\81v
2091       Canvas.Font.Color := clWindowText;
2092       Canvas.Font.Style := [];
2093       AlignRight := true;
2094     end else if (Index > 0) then
2095     begin
2096       // \83S\81[\83X\83g\96¼\82ð\91I\91ð
2097       if SakuraSeeker.ProcessByName[Items[Index]] = nil then
2098         Canvas.Font.Color := clRed // \91\8dÝ\82µ\82È\82¢\83S\81[\83X\83g
2099       else
2100         Canvas.Font.Color := clBlue; // \91\8dÝ\82·\82é\83S\81[\83X\83g
2101       Canvas.Font.Style := [fsBold];
2102     end else
2103     begin
2104       Canvas.Font.Color := clWindowText;
2105       Canvas.Font.Style := [];
2106     end;
2107     if odSelected in State then
2108       Canvas.Font.Color := clHighlightText;
2109     // \95`\89æ
2110     if AlignRight then
2111     begin
2112       w := Canvas.TextWidth(cbxTargetGhost.Items[Index]);
2113       Canvas.TextRect(Rect, Rect.Right - w, Rect.Top,
2114         cbxTargetGhost.Items[Index]);
2115     end else
2116       Canvas.TextRect(Rect, Rect.Left, Rect.Top,
2117         cbxTargetGhost.Items[Index]);
2118   end;
2119 end;
2120
2121 procedure TfrmSender.FormCloseQuery(Sender: TObject;
2122   var CanClose: Boolean);
2123 begin
2124   if (not Pref.ConfirmOnExit) or FEndSession then
2125     Exit;
2126   if MessageDlg('SSTP Bottle Client\82ð\8fI\97¹\82µ\82Ü\82·', mtConfirmation,
2127                 mbOkCancel, 0) = mrCancel then
2128     CanClose := false;
2129 end;
2130
2131 procedure TfrmSender.UpdateIfGhostBox;
2132 var
2133   Selected: String;
2134   i: integer;
2135   HiddenCount: integer;
2136 begin
2137   cbxTargetGhost.DropDownCount := Pref.GhostDropDownCount;
2138   Selected := cbxTargetGhost.Text;
2139   HiddenCount := 0;
2140   with cbxTargetGhost do begin
2141     Items.BeginUpdate;
2142     Items.Clear;
2143     Items.Add(ChannelDefault);
2144     for i := 0 to SakuraSeeker.Count-1 do begin
2145       // \94j\91¹FMO\91Î\8dô\81BHWND\82Ì\92f\95Ð\82ª\8ec\82Á\82Ä\82¢\82é\82ªName\82ª\8fÁ\82¦\82Ä\82¢\82é\8fê\8d\87\82ª\82 \82é
2146       if Length(SakuraSeeker[i].Name) = 0 then Continue;
2147       if Pref.HideGhosts and not FTargetGhostExpand then
2148         if Pref.VisibleGhostsList.IndexOf(SakuraSeeker[i].Name) < 0 then
2149         begin
2150           Inc(HiddenCount);
2151           Continue;
2152         end;
2153       if cbxTargetGhost.Items.IndexOf(SakuraSeeker[i].Name) < 0 then
2154         cbxTargetGhost.Items.Add(SakuraSeeker[i].Name);
2155     end;
2156     cbxTargetGhost.ItemIndex := 0;
2157     if (Length(Selected) > 0) and (Selected <> ChannelDefault) then begin
2158       with cbxTargetGhost do begin
2159         for i := 1 to Items.Count-1 do begin
2160           if Items[i] = Selected then
2161             ItemIndex := i;
2162         end;
2163         //\83S\81[\83X\83g\82ª\93Ë\91R\91\8dÝ\82µ\82È\82­\82È\82Á\82½\8fê\8d\87\91Î\8dô
2164         if ItemIndex = 0 then begin
2165           Items.Add(Selected);
2166           ItemIndex := Items.Count - 1;
2167         end;
2168       end;
2169     end;
2170     if Pref.HideGhosts and not FTargetGhostExpand then
2171       Items.Add(Format('\82·\82×\82Ä(%d)...', [HiddenCount]));
2172     Items.EndUpdate;
2173   end;
2174 end;
2175
2176 procedure TfrmSender.HTTPFailure(Sender: TObject);
2177 begin
2178   SysUtils.Beep;
2179   Beep;
2180   ShowHintLabel('SSTP Bottle\83T\81[\83o\82Æ\82Ì\90Ú\91±\82É\8e¸\94s\82µ\82Ü\82µ\82½', WarningColor);
2181   ShowMessage('SSTP Bottle\83T\81[\83o\82Æ\82Ì\90Ú\91±\82É\8e¸\94s\82µ\82Ü\82µ\82½'#13#10 +
2182     (Sender as THTTPDownloadThread).LastErrorMessage);
2183   Connecting := false;
2184 end;
2185
2186 procedure TfrmSender.actPrevGhostExecute(Sender: TObject);
2187 var i: integer;
2188 begin
2189   SakuraSeeker.BeginDetect;
2190   UpdateIfGhostBox;
2191   i := cbxTargetGhost.ItemIndex;
2192   Dec(i);
2193   if i <= -1 then
2194   begin
2195     i := cbxTargetGhost.Items.Count-1;
2196     if Pref.HideGhosts and not FTargetGhostExpand then
2197       i := i - 1;
2198   end;
2199   cbxTargetGhost.ItemIndex := i;
2200   cbxTargetGhostChange(self);
2201 end;
2202
2203 procedure TfrmSender.actNextGhostExecute(Sender: TObject);
2204 var i: integer;
2205 begin
2206   SakuraSeeker.BeginDetect;
2207   UpdateIfGhostBox;
2208   i := cbxTargetGhost.ItemIndex;
2209   Inc(i);
2210   if Pref.HideGhosts and not FTargetGhostExpand then
2211   begin
2212     if  i > cbxTargetGhost.Items.Count-2 then i := 0;
2213   end else
2214   begin
2215     if  i > cbxTargetGhost.Items.Count-1 then i := 0;
2216   end;
2217   cbxTargetGhost.ItemIndex := i;
2218   cbxTargetGhostChange(self);
2219 end;
2220
2221 procedure TfrmSender.actResetGhostExecute(Sender: TObject);
2222 begin
2223   cbxTargetGhost.ItemIndex := 0; // (CH\90\84\8f§)\82É\96ß\82·
2224   FTargetGhostExpand := false;
2225   if Visible then memScript.SetFocus;
2226   cbxTargetGhostChange(self);
2227 end;
2228
2229 procedure TfrmSender.timDisconnectCheckTimerTimer(Sender: TObject);
2230 begin
2231   if (IdSlpp20.LastReadTimeInterval > Pref.ReconnectWait * 60000) then begin
2232     SysUtils.Beep;
2233     frmLog.AddCurrentSystemLog('SYSTEM', 'SSTP Bottle\83T\81[\83o\82Æ\82Ì\90Ú\91±\82ª\83^\83C\83\80\83A\83E\83g\82µ\82Ü\82µ\82½');
2234     if IdSlpp20.Connected then IdSlpp20.Disconnect;
2235   end;
2236   if not IdSlpp20.Connected then begin
2237     if Added then begin
2238       Slpp20Disconnect(self); //\82È\82º\82©Disconnect\83C\83x\83\93\83g\82ª\8bN\82±\82ç\82¸\82É\90Ø\92f\82µ\82½\8fê\8d\87
2239     end else begin
2240       //\90Ø\92f\82µ\82½\82Ü\82Ü\8dÄ\90Ú\91±\82Å\82«\82¸\95ú\92u\82³\82ê\82Ä\82¢\82é\8fê\8d\87\82à\88ê\92è\8e\9e\8aÔ\92u\82«\82É\8dÄ\90Ú\91±\83g\83\89\83C
2241       //\82½\82¾\82µ\89ñ\90\94\90§\8cÀ\82 \82è
2242       RetryBeginConnect;
2243     end;
2244   end;
2245 end;
2246
2247 procedure TfrmSender.RetryBeginConnect;
2248 begin
2249   if FBeginConnectFailCount < 3 then begin
2250     // \90Ø\92f\82³\82ê\82Ä\82¢\82ê\82Î\8dÄ\90Ú\91±
2251     FAutoAddAfterGetChannel := true;
2252     BeginConnect;
2253   end else if FBeginConnectFailCount = 3 then begin
2254     frmLog.AddCurrentSystemLog('SYSTEM', '\8dÄ\90Ú\91±\8e©\93®\83\8a\83g\83\89\83C\82ð\92\86\8e~\82µ\82Ü\82·');
2255     frmMessageBox.ShowMessage(
2256       'SSTP Bottle\83T\81[\83o\82É\90Ú\91±\82Å\82«\82Ü\82¹\82ñ\81B'#13#10+
2257       '\83l\83b\83g\83\8f\81[\83N\82É\90Ú\91±\82µ\82Ä\82¢\82é\82±\82Æ\82ð\8am\94F\82µ\82½\8cã\82Å\81A\83`\83\83\83\93\83l\83\8b\8eQ\89Á\83{\83^\83\93\82ð\89\9f\82µ\82Ä\82­\82¾\82³\82¢\81B'#13#10+
2258       'SSTP Bottle\83T\81[\83o\82ª\83_\83E\83\93\82µ\82Ä\82¢\82é\8fê\8d\87\82Í\81A\82µ\82Î\82ç\82­\82µ\82Ä\82©\82ç\8dÄ\90Ú\91±\82µ\82Ä\82­\82¾\82³\82¢\81B'
2259     );
2260     Inc(FBeginConnectFailCount);
2261   end;
2262 end;
2263
2264 procedure TfrmSender.actDownloadLogExecute(Sender: TObject);
2265 var BottleLog: TBottleLogList;
2266     Title: String;
2267     Cond: TBottleLogDownloadCondition;
2268     NewIndex: integer;
2269   function TimeStr(Mins: integer): String;
2270   var day, hour, min: integer;
2271   begin
2272     day := Mins div (60 * 24);
2273     hour := (Mins div 60) mod 24;
2274     min := Mins mod 60;
2275     Result := '';
2276     if day  > 0 then Result := Result + Format('%d\93ú', [day]);
2277     if hour > 0 then Result := Result + Format('%d\8e\9e\8aÔ', [hour]);
2278     if (min  > 0) or (Result = '') then Result := Result + Format('%d\95ª', [min]);
2279   end;
2280 begin
2281   Application.CreateForm(TfrmLogDownload, frmLogDownload);
2282   try
2283     if frmLogDownload.Execute then begin
2284       with frmLogDownload do begin
2285         if IsRange then begin
2286           if CompareDate(DateLo, DateHi) = 0 then
2287             Title := FormatDateTime('yy-mm-dd', DateLo)
2288           else
2289             Title := FormatDateTime('yy-mm-dd', DateLo) + ' - ' + FormatdateTime('yy-mm-dd', DateHi);
2290         end else begin
2291           Title := Format('\89ß\8b\8e%s', [TimeStr(RecentCount)]);
2292         end;
2293         if Channel <> '' then Title := Title + '(' + Channel + ')';
2294       end;
2295       BottleLog := TBottleLogList.Create(Title);
2296       try
2297         BottleLog.OnLoaded := frmLog.LogLoaded;
2298         BottleLog.OnLoadFailure := frmLog.LogLoadFailure;
2299         BottleLog.OnLoadWork := frmLog.LogLoadWork;
2300         with frmLogDownload do begin
2301           Cond.IsRange := IsRange;
2302           Cond.RecentCount := RecentCount;
2303           Cond.DateLo := DateLo;
2304           Cond.DateHi := DateHi;
2305           Cond.MinVote := MinVote;
2306           Cond.MinAgree := MinAgree;
2307           Cond.Channel := Channel;
2308         end;
2309         BottleLog.LoadFromWeb(Cond);
2310       except
2311         FreeAndNil(BottleLog);
2312       end;
2313       if BottleLog <> nil then begin
2314         NewIndex := frmLog.BottleLogList.Add(BottleLog);
2315         frmLog.UpdateTab;
2316         frmLog.tabBottleLog.TabIndex := NewIndex;
2317         frmLog.UpdateWindow;
2318       end;
2319     end;
2320   finally
2321     frmLogDownload.Release;
2322   end;
2323 end;
2324
2325 function TfrmSender.BuildMenuConditionCheck(const IfGhost,
2326   Ghost: String): boolean;
2327 var i: integer;
2328     Cond: String;
2329 begin
2330   i := 0;
2331   Result := true;
2332   repeat
2333     Cond := Token(IfGhost, ',', i);
2334     if Cond <> '' then begin
2335       if Cond[1] = '!' then begin
2336         Cond := Copy(Cond, 2, High(integer));
2337         if Cond = Ghost then Result := false;
2338       end else begin
2339         if Cond <> Ghost then Result := false;
2340       end;
2341     end;
2342     Inc(i);
2343   until Cond = '';
2344 end;
2345
2346 procedure TfrmSender.BuildMenu(Root: TMenuItem; Simple: boolean);
2347 var i, j, k, count: integer;
2348     ConstData: TScriptConst;
2349     Menu1, Menu2: TMenuItem;
2350     Ghost: String;
2351 begin
2352   // Simple = false \82Ì\8fê\8d\87\82Í\83\81\83j\83\85\81[\82ð\8a®\91S\82É\8dÄ\8d\\92z\82·\82é\81B
2353   // Simple = true \82Ì\8fê\8d\87\82Í\83S\81[\83X\83g\8aÖ\8cW\82Ì\82Ý\8dÄ\8d\\92z\82·\82é\82Ì\82Å\8d\82\91¬\81B
2354   if cbxTargetGhost.ItemIndex > 0 then Ghost := cbxTargetGhost.Text
2355   else if FNowChannel <> '' then Ghost := ChannelList.Channel[FNowChannel].Ghost;
2356
2357   // \8aù\91\82Ì\83\81\83j\83\85\81[\8dí\8f\9c
2358   if Simple then begin
2359     // IfGhost\8fð\8c\8f\95t\82«\83\81\83j\83\85\81[\82Ì\82Ý\8dí\8f\9c
2360     for i := Root.Count-1 downto 0 do begin
2361       if ScriptConstList.GetMenuByID(Root.Items[i].Tag).IfGhost <> '' then
2362         Root.Items[i].Free;
2363     end;
2364   end else begin
2365     // \91S\95\94\8dí\8f\9c
2366     for i := Root.Count-1 downto 0 do begin
2367       Root.Items[i].Free;
2368     end;
2369   end;
2370
2371   count := -1;
2372   for i := 0 to ScriptConstList.Count-1 do begin
2373     for j := 0 to ScriptConstList[i].Count-1 do begin
2374       // \83S\81[\83X\83g\88á\82¢\82Ì\8fê\8d\87\82Í\83X\83L\83b\83v
2375       if not BuildMenuConditionCheck(ScriptConstList[i][j].IfGhost, Ghost) then Continue;
2376       Inc(count);
2377       // Simple\82Ì\8fê\8d\87\82Í\8aù\82É\8aY\93\96\83\81\83j\83\85\81[\82ª\91\8dÝ\82·\82é\82±\82Æ\82ª\82 \82é\82Ì\82Å\83X\83L\83b\83v
2378       if Simple and (count < Root.Count) then
2379         if (Root.Items[count].Tag = ScriptConstList[i][j].ID) then begin
2380           Continue;
2381         end;
2382
2383       Menu1 := TMenuItem.Create(Root);
2384       Menu1.Caption := ScriptConstList[i][j].Caption;
2385       Menu1.Hint    := ScriptConstList[i][j].Caption;
2386       Menu1.AutoHotkeys := maManual;
2387       Menu1.Tag := ScriptConstList[i][j].ID;
2388       Menu1.OnClick := mnConstGroupClick;
2389
2390       if not Simple then begin
2391         Root.Add(Menu1);
2392       end else begin
2393         if count < Root.Count-1 then
2394           Root.Insert(count, Menu1)
2395         else
2396           Root.Add(Menu1);
2397       end;
2398
2399       Menu1.Enabled := ScriptConstList[i][j].Count > 0;
2400       for k := 0 to ScriptConstList[i][j].Count-1 do begin
2401         ConstData := ScriptConstList[i][j][k];
2402         Menu2 := TMenuItem.Create(Root);
2403         Menu2.Caption := ConstData.Caption;
2404         Menu2.Hint := ConstData.ConstText;
2405         // if ConstData.ShortCut <> 0 then Menu2.Hint := Menu2.Hint
2406         //   + ' (' + ShortCutToText(ConstData.ShortCut) + ')';
2407         // \83T\81[\83t\83B\83X\83v\83\8c\83r\83\85\81[\8eÀ\8c»\82Ì\82½\82ß\8fã\8dí\8f\9c
2408         Menu2.ShortCut := ConstData.ShortCut;
2409         Menu2.OnClick := mnConstClick;
2410         Menu2.AutoHotkeys := maManual;
2411         Menu2.Tag := ConstData.ID;
2412         if (k mod 15 = 0) and (k > 0) then Menu2.Break := mbBarBreak;
2413         Menu1.Add(Menu2);
2414       end;
2415     end;
2416   end;
2417 end;
2418
2419 procedure TfrmSender.cbxTargetGhostChange(Sender: TObject);
2420 begin
2421   // \81u\82·\82×\82Ä\95\\8e¦\81v\82ð\91I\91ð\82³\82ê\82½\8fê\8d\87\82Í\83S\81[\83X\83g\91I\91ð\83{\83b\83N\83X\82ð\8dÄ\8d\\92z
2422   if Pref.HideGhosts and not FTargetGhostExpand then
2423   begin
2424     with cbxTargetGhost do
2425     begin
2426       // \88ê\94Ô\89º\82Ì\83A\83C\83e\83\80\82ª\91I\91ð\82³\82ê\82½\82Æ\82«\81B
2427       // \82½\82¾\82µItemIndex=0\82Ì\8fê\8d\87(\83S\81[\83X\83g\82ª\8bN\93®\82µ\82Ä\82¢\82È\82¢\8fê\8d\87)\82Í\97á\8aO
2428       if (ItemIndex = Items.Count-1) and (ItemIndex > 0) then
2429       begin
2430         FTargetGhostExpand := true;
2431         UpdateIfGhostBox;
2432         ItemIndex := 0;
2433         DroppedDown := true;
2434       end;
2435     end;
2436   end;
2437   // \92è\8c^\8bå\83\81\83j\83\85\81[\82ð\8dÄ\8d\\92z
2438   ConstructMenu(true);
2439   // \83v\83\8c\83r\83\85\81[\82ª\82 \82é\8fê\8d\87\82Í\83v\83\8c\83r\83\85\81[
2440   EditorPreview;
2441 end;
2442
2443 procedure TfrmSender.PlaySound(const FileName: String);
2444 begin
2445   if Pref.SilentWhenHidden and not Application.ShowMainForm then Exit;
2446   try
2447     MediaPlayer.FileName := FileName;
2448     MediaPlayer.Open;
2449     MediaPlayer.Play;
2450   except
2451     on E: EMCIDeviceError do begin
2452       ShowMessage('\83T\83E\83\93\83h\8dÄ\90\83G\83\89\81[:'#13#10 + FileName + #13#10#13#10 + E.Message);
2453     end;
2454   end;
2455 end;
2456
2457 procedure TfrmSender.actFMOExplorerExecute(Sender: TObject);
2458 begin
2459   try
2460     if not Assigned(frmFMOExplorer) then
2461       Application.CreateForm(TfrmFMOExplorer, frmFMOExplorer);
2462   except
2463     on E: Exception do
2464       ShowMessage('FMO\83G\83N\83X\83v\83\8d\81[\83\89\82ð\95\\8e¦\82Å\82«\82Ü\82¹\82ñ\81B'#13#10#13#10 +
2465         E.Message);
2466   end;
2467   frmFMOExplorer.Show;
2468 end;
2469
2470 procedure TfrmSender.SaveChainRuleList;
2471 var Str: TStringList;
2472 begin
2473   Str := TStringList.Create;
2474   try
2475     Str.Text := ComponentToString(BottleChainRuleList);
2476     Str.SaveToFile(ExtractFileDir(Application.ExeName)+'\rule.txt');
2477   finally
2478     Str.Free;
2479   end;
2480 end;
2481
2482 procedure TfrmSender.BottleSstpResendEnd(Sender: TObject; MID: String);
2483 begin
2484   frmLog.SetBottleState(MID, lsOpened);
2485 end;
2486
2487 procedure TfrmSender.BottleSstpResendTrying(Sender: TObject; MID: String);
2488 begin
2489   frmLog.SetBottleState(MID, lsPlaying);
2490 end;
2491
2492 procedure TfrmSender.actInsertCueExecute(Sender: TObject);
2493 var InsertItem: TLogItem;
2494     i, errCount, Res: integer;
2495     Log: TBottleLogList;
2496     ErrorMes: String; // \83X\83N\83\8a\83v\83g\82Ì\83G\83\89\81[\82Ì\93à\97e
2497 begin
2498   if FBottleSstp.CueCount > 0 then begin
2499     if MessageDlg(Format('\8c»\8dÝ\8dÄ\91\97\83L\83\85\81[\82É\93ü\82Á\82Ä\82¢\82é%d\8c\8f\82Ì\96¢\94z\91\97\83{\83g\83\8b\82ð\83N\83\8a\83A\82µ\82Ä\81A'+
2500       '\83\8d\83O\83E\83B\83\93\83h\83E\82É\82 \82é\83{\83g\83\8b\82ð\98A\91±\8dÄ\90\82µ\82Ü\82·\81B'#13#10+
2501       '\90V\92\85\83\81\83b\83Z\81[\83W\82Í\82»\82Ì\8cã\82É\8dÄ\90\82³\82ê\82Ü\82·\81B', [FBottleSstp.CueCount]),
2502       mtWarning, mbOkCancel, 0) = mrCancel then Exit;
2503   end;
2504   FBottleSstp.Clear;
2505   frmLog.AllBottleOpened;
2506   if frmLog.lvwLog.Selected = nil then Exit;
2507   Log := frmLog.SelectedBottleLog;
2508   if Log = nil then Exit;
2509   FBottleSSTP.OnResendCountChange := nil;
2510   errCount := 0;
2511   for i := frmLog.lvwLog.Selected.Index downto 0 do begin
2512     if (Log[i] as TLogItem).LogType <> ltBottle then Continue;
2513     InsertItem := TLogItem.Create(Log[i] as TLogItem);
2514     try
2515       InsertItem.Script := ScriptTransForSSTP(InsertItem.Script, ErrorMes);
2516       if ErrorMes <> '' then
2517       begin
2518         Res := MessageDlg('\83X\83N\83\8a\83v\83g\82É\96â\91è\82ª\82 \82é\89Â\94\\90«\82ª\82 \82è\82Ü\82·\81B' +
2519           '\8dÄ\90\82µ\82Ü\82·\82©?'#13#10 + ErrorMes, mtWarning,
2520           mbYesNoCancel, 0);
2521         if Res = mrNo then
2522           raise Exception.Create('Script Syntax Error')
2523         else if Res = mrCancel then
2524         begin
2525           InsertItem.Free;
2526           FBottleSstp.Clear;
2527           frmLog.AllBottleOpened;
2528           Break;
2529         end;
2530       end;
2531       if InsertItem.Ghost = '' then begin
2532         if ChannelList.Channel[InsertItem.Channel] <> nil then
2533         InsertItem.Ghost := ChannelList.Channel[InsertItem.Channel].Ghost;
2534       end;
2535       FBottleSSTP.Push(InsertItem);
2536       frmLog.SetBottleState(InsertItem.MID, lsUnopened);
2537     except
2538       InsertItem.Free;
2539       Inc(errCount);
2540     end;
2541   end;
2542   if errCount > 0 then
2543     ShowMessage(Format('%d\8c\8f\82Ì\83{\83g\83\8b\82É\96â\91è\82ª\82 \82Á\82½\82½\82ß\8dÄ\90\82Å\82«\82Ü\82¹\82ñ\81B', [errCount]));
2544   FBottleSSTP.OnResendCountChange := BottleSstpResendCountChange;
2545   BottleSstpResendCountChange(self);
2546   frmLog.lvwLog.Invalidate;
2547 end;
2548
2549 function TfrmSender.ScriptTransForSSTP(const Script: String;
2550   out Error: String): String;
2551 var TransOpt: TScriptTransOptions;
2552 begin
2553   if Pref.NoTransURL then
2554     TransOpt := [toConvertURL, toNoChoice, toWaitScriptEnd]
2555   else
2556     TransOpt := [toConvertURL, toWaitScriptEnd];
2557   if Pref.IgnoreFrequentYenS then TransOpt := TransOpt + [toIgnoreFrequentYenS];
2558   if Pref.FixMessySurface then TransOpt := TransOpt + [toFixMessySurface];
2559   if Pref.HUTagTo01Tag then TransOpt := TransOpt + [toHUTagTo01Tag];
2560   Result := Script;
2561   Error := DoTrans(Result, TransOpt);
2562 end;
2563
2564 procedure TfrmSender.FormResize(Sender: TObject);
2565 var w: integer;
2566 begin
2567   // \83G\83f\83B\83^\81[\95\94\95ª\82Ì\83\8f\81[\83h\83\89\83b\83v\95\9d\82ð\92²\90®\82·\82é
2568   if memScript.ColWidth <> 0 then
2569   begin
2570     with memScript do
2571     begin
2572       w := Width - LeftMargin - ColWidth div 2;
2573       if ScrollBars in [ssVertical, ssBoth] then
2574         w := w - GetSystemMetrics(SM_CYVSCROLL);
2575       WrapOption.WrapByte := w div ColWidth;
2576     end;
2577   end;
2578 end;
2579
2580 procedure TfrmSender.actCopyExecute(Sender: TObject);
2581 begin
2582   memScript.CopyToClipboard;
2583 end;
2584
2585 procedure TfrmSender.actPasteExecute(Sender: TObject);
2586 begin
2587   memScript.PasteFromClipboard;
2588 end;
2589
2590 procedure TfrmSender.actCutExecute(Sender: TObject);
2591 begin
2592   memScript.CutToClipboard;
2593 end;
2594
2595 procedure TfrmSender.actSelectAllExecute(Sender: TObject);
2596 begin
2597   memScript.SelectAll;
2598 end;
2599
2600 procedure TfrmSender.actUndoExecute(Sender: TObject);
2601 begin
2602   memScript.Undo;
2603 end;
2604
2605 procedure TfrmSender.actRedoExecute(Sender: TObject);
2606 begin
2607   memScript.Redo;
2608 end;
2609
2610 function TfrmSender.IsSurfaceTag(const Script: String;
2611   var ID: integer): boolean;
2612 begin
2613   Result := false;
2614   if SsParser.Match(Script, '\s%d') = 3 then
2615   begin
2616     Result := true;
2617     ID := Ord(Script[3]) - Ord('0')
2618   end
2619   else if (Length(Script) > 0) and (SsParser.Match(Script, '\s[%D]') = Length(Script)) then
2620   begin
2621     Result := true;
2622     ID := StrToIntDef(SsParser.GetParam(Script, 1), 0);
2623   end;
2624 end;
2625
2626 procedure TfrmSender.memScriptMouseMove(Sender: TObject;
2627   Shift: TShiftState; X, Y: Integer);
2628 var id: integer;
2629     token: String;
2630 begin
2631   // \95Ò\8fW\83E\83B\83\93\83h\83E\82Å\83}\83E\83X\83|\83C\83\93\83g\82·\82é\82Æ\83T\81[\83t\83B\83X\83v\83\8c\83r\83\85\81[
2632   if not Pref.SurfacePreviewOnScriptPoint then
2633     Exit;
2634   token := memScript.TokenStringFromPos(Point(X, Y));
2635   if IsSurfaceTag(token, id) then
2636   begin
2637     DoSurfacePreview(id, spEditor);
2638   end else
2639   begin
2640     frmSurfacePreview.HideAway;
2641   end;
2642 end;
2643
2644 procedure TfrmSender.DoSurfacePreview(Surface: integer;
2645   const Kind: TSurfacePreviewType);
2646 var Ghost: String;
2647     Bmp: TBitmap;
2648     CPos: TPoint;
2649 begin
2650   if cbxTargetGhost.ItemIndex > 0 then
2651     ghost := cbxTargetGhost.Text
2652   else if FNowChannel <> '' then
2653     ghost := ChannelList.Channel[FNowChannel].Ghost;
2654
2655   // \93ñ\8fd\95\\8e¦\82Ì\97}\90§
2656   if (FVisiblePreviewGhost = Ghost) and (FVisiblePreviewSurface = Surface) and
2657     not (frmSurfacePreview.IsHidden) then
2658   begin
2659     Exit;
2660   end;
2661
2662   if ghost <> '' then
2663   begin
2664     Bmp := TBitmap.Create;
2665     try
2666       if Spps.TryGetImage(ghost, Surface, Bmp) then
2667       begin
2668         case Kind of
2669           spHint:
2670             CPos := GetSurfacePreviewPositionHint(Bmp.Width, Bmp.Height);
2671           spEditor:
2672             CPos := GetSurfacePreviewPositionScriptPoint(Bmp.Width, Bmp.Height);
2673           else
2674             CPos := Point(0, 0);
2675         end;
2676         frmSurfacePreview.ShowPreview(Bmp, CPos.X, CPos.Y);
2677         FVisiblePreviewGhost := Ghost;
2678         FVisiblePreviewSurface := Surface;
2679       end else
2680         frmSurfacePreview.HideAway;
2681     finally
2682       Bmp.Free;
2683     end;
2684   end;
2685 end;
2686
2687 function TfrmSender.GetSurfacePreviewPositionHint(w, h: integer): TPoint;
2688 {var MousePoint: TPoint;
2689     MenuRect: TRect;}
2690 begin
2691   // \83T\81[\83t\83B\83X\83v\83\8c\83r\83\85\81[\83E\83B\83\93\83h\83E\82Ì\95\\8e¦\88Ê\92u\82ð\8c\88\92è\82·\82é
2692   // \91\97\90M\83E\83B\83\93\83h\83E\82Ì\88Ê\92u\82É\82æ\82Á\82Ä\82Í\96­\82È\82Æ\82±\82ë\82É\83\81\83j\83\85\81[\82ª\95\\8e¦\82³\82ê\82Ä\82¢\82é\82Ì\82Å
2693   // \88Ä\8aO\82â\82â\82±\82µ\82¢
2694   {GetCursorPos(MousePoint);
2695   OutputDebugString(PChar(IntToStr(FVisibleMenuItem.Count)));
2696   //if GetMenuItemRect(Self.Handle, FVisibleMenuItem.Items[0].Handle, 1, MenuRect) then ;
2697   Result := Point(MenuRect.Left-10, MenuRect.Top-10);}
2698   Result := GetSurfacePreviewPositionScriptPoint(w, h);
2699 end;
2700
2701 function TfrmSender.GetSurfacePreviewPositionScriptPoint(w, h: integer): TPoint;
2702 var MousePoint: TPoint;
2703 begin
2704   GetCursorPos(MousePoint);
2705   case Pref.SurfacePreviewOnScriptPointPosition of
2706     spspMainWindowRight:
2707       Result := Point(Self.Left + Self.Width, MousePoint.Y);
2708   else
2709       Result := Point(Self.Left - w, MousePoint.Y);
2710   end;
2711 end;
2712
2713 procedure TfrmSender.mnConstGroupClick(Sender: TObject);
2714 begin
2715   if (Sender is TMenuItem) then
2716     FVisibleMenuItem := Sender as TMenuItem;
2717 end;
2718
2719 procedure TfrmSender.actRecallScriptBufferExecute(Sender: TObject);
2720 begin
2721   if FScriptBuffer.Count = 0 then
2722     Exit;
2723   memScript.Lines.Assign(FScriptBuffer[0] as TStringList);
2724   memScriptChange(Self);
2725   ShowHintLabel('\83X\83N\83\8a\83v\83g\82ð\8cÄ\82Ñ\8fo\82µ\82Ü\82µ\82½');
2726 end;
2727
2728 procedure TfrmSender.EditorPreview;
2729 var Ghost, Script: String;
2730 begin
2731   if frmEditorTalkShow <> nil then
2732     if frmEditorTalkShow.Visible then
2733     begin
2734       Script := StringReplace(GetScriptText, #13#10, '', [rfReplaceAll]);
2735       Ghost := '';
2736       if cbxTargetGhost.ItemIndex > 0 then
2737         Ghost := cbxTargetGhost.Text
2738       else if FNowChannel <> '' then
2739         Ghost := ChannelList.Channel[FNowChannel].Ghost;
2740       frmEditorTalkShow.TalkShowFrame.View(Script, Ghost);
2741     end;
2742 end;
2743
2744 procedure TfrmSender.actEditorPreviewExecute(Sender: TObject);
2745 begin
2746   if frmEditorTalkShow <> nil then
2747     frmEditorTalkShow.Show
2748   else
2749   begin
2750     Application.CreateForm(TfrmEditorTalkShow, frmEditorTalkShow);
2751     frmEditorTalkShow.Show;
2752   end;
2753   EditorPreview;
2754 end;
2755
2756 // \83v\83\89\83O\83C\83\93\83\8a\83Z\83b\83g
2757 procedure TfrmSender.actResetPluginsExecute(Sender: TObject);
2758 begin
2759   Spps.ClearImagePool;
2760   Spps.LoadFromDirectory(FSppDir);
2761 end;
2762
2763 procedure TfrmSender.IdSLPP20Connect(Sender: TObject);
2764 begin
2765   ShowHintLabel('SSTP Bottle\83T\81[\83o\82ª\8c©\82Â\82©\82è\82Ü\82µ\82½');
2766 end;
2767
2768 // \83X\83N\83\8a\83v\83g\92\86\82Ì\83^\83O\82ð\92u\8a·\82·\82é
2769 // \83T\83C\83Y\89Â\95Ï\82Ì\94z\97ñ\83p\83\89\83\81\81[\83^\94Å
2770 function TfrmSender.TagReplace(Script: String; Before,
2771   After: array of String): String;
2772 var BeforeList, AfterList: TStringList;
2773     i: integer;
2774 begin
2775   BeforeList := TStringList.Create;
2776   AfterList  := TStringList.Create;
2777   try
2778     for i := Low(Before) to High(Before) do
2779       BeforeList.Add(Before[i]);
2780     for i := Low(After) to High(After) do
2781       AfterList.Add(After[i]);
2782     Result := TagReplace(Script, BeforeList, AfterList);
2783   finally
2784     BeforeList.Free;
2785     AfterList.Free;
2786   end;
2787 end;
2788
2789 // \83X\83N\83\8a\83v\83g\92\86\82Ì\83^\83O\82ð\92u\8a·\82·\82é
2790 // StringReplace\82Æ\88á\82Á\82Ä\90³\8am\82É\83^\83O\82É\83}\83b\83`\82µ\81A
2791 // \82Ü\82½\83p\83^\81[\83\93\82ð\95¡\90\94\8ew\92è\82Å\82«\82é(\92u\8a·\8cã\82Ì\8c\8b\89Ê\82ª\82Ü\82½\92u\8a·\82³\82ê\82½\82è\82µ\82È\82¢)
2792 function TfrmSender.TagReplace(Script: String; Before,
2793   After: TStrings): String;
2794 var i, j: integer;
2795     Flag, OldLeaveEscape, OldEscapeInvalidMeta: boolean;
2796     OldStr: String;
2797 begin
2798   Result := '';
2799   with SsParser do
2800   begin
2801     OldStr := InputString;
2802     OldLeaveEscape := LeaveEscape;
2803     OldEscapeInvalidMeta := EscapeInvalidMeta;
2804     LeaveEscape := true;
2805     EscapeInvalidMeta := false;
2806     InputString := Script;
2807   end;
2808   for i := 0 to SsParser.Count-1 do
2809   begin
2810     Flag := false;
2811     for j := 0 to Before.Count-1 do
2812     begin
2813       if (SsParser.MarkUpType[i] = mtTag) and (SsParser[i] = Before[j]) then
2814       begin
2815         Flag := true;
2816         Result := Result + After[j];
2817       end;
2818     end;
2819     if not Flag then
2820       Result := Result + SsParser[i];
2821   end;
2822   with SsParser do
2823   begin
2824     LeaveEscape := OldLeaveEscape;
2825     EscapeInvalidMeta := OldEscapeInvalidMeta;
2826     InputString := OldStr;
2827   end;
2828 end;
2829
2830 // WndProc\82ð\83I\81[\83o\81[\83\89\83C\83h\82µ\82Ä\81AFWM_TaskBarCraeted\82É
2831 // \91Î\89\9e\82·\82é
2832 procedure TfrmSender.WndProc(var Message: TMessage);
2833 begin
2834   if (Message.Msg = FWM_TaskBarCreated) and (FWM_TaskBarCreated <> 0) then
2835   begin
2836     TaskTray.Registered := false; // TTaskTray\82É\83^\83X\83N\83g\83\8c\83C\82ª\8fÁ\82¦\82½\82±\82Æ\82ð
2837                                   // \8bC\82Ã\82©\82¹\82é
2838     ChangeTaskIcon;
2839   end
2840   else
2841     inherited;
2842 end;
2843
2844 // \92u\8a·
2845 procedure TfrmSender.actReplaceExecute(Sender: TObject);
2846 var
2847   Form: TfrmStrReplaceDialog;
2848   Lines: String;
2849   Options: TReplaceFlags;
2850 begin
2851   Application.CreateForm(TfrmStrReplaceDialog, Form);
2852   try
2853     if Form.Execute then
2854     begin
2855       with Form.Pair do
2856       begin
2857         Lines := memScript.Lines.Text;
2858         Options := [rfReplaceAll];
2859         if IgnoreCase then
2860           Options := Options + [rfIgnoreCase];
2861         if UseRegExp then
2862           Lines := StringReplaceRegExp(Lines, BeforeStr, AfterStr, Options)
2863         else
2864           Lines := StringReplace(Lines, BeforeStr, AfterStr, Options);
2865       end;
2866       if Lines <> memScript.Lines.Text then
2867       begin
2868         memScript.SelectAll;
2869         memScript.SelText := Lines;
2870       end;
2871     end;
2872   finally
2873     Form.Release;
2874   end;
2875 end;
2876
2877 procedure TfrmSender.actSendToEditorExecute(Sender: TObject);
2878 var Log: TLogItem;
2879 begin
2880   if frmLog.lvwLog.Selected = nil then Exit;
2881   Log := frmLog.SelectedBottleLog[frmLog.lvwLog.Selected.Index] as TLogItem;
2882   if Log = nil then Exit;
2883   CopyFromLogToEditor(Log);
2884 end;
2885
2886 procedure TfrmSender.actSendToLogWindowExecute(Sender: TObject);
2887 var Ghost, Script: String;
2888 begin
2889   YenETrans;
2890   Script := StringReplace(GetScriptText, #13#10, '', [rfReplaceAll]);
2891   if cbxTargetGhost.ItemIndex > 0 then
2892     Ghost := cbxTargetGhost.Text
2893   else
2894     Ghost := '';
2895   frmLog.AddCurrentScriptLog('\83N\83\8a\83b\83v', Script, ClipChannel, '', Ghost);
2896   ClearEditor;
2897 end;
2898
2899 procedure TfrmSender.memScriptDragOver(Sender, Source: TObject; X,
2900   Y: Integer; State: TDragState; var Accept: Boolean);
2901 begin
2902   // \83\8d\83O\83E\83B\83\93\83h\83E\82©\82ç\82Ì\83\8d\83O\83A\83C\83e\83\80\82Ì\92¼\90ÚD&D\82ð\8b\96\89Â\82·\82é
2903   if Source is TBottleLogDragObject then
2904     Accept := (Source as TBottleLogDragObject).LogItem.LogType = ltBottle
2905 end;
2906
2907 procedure TfrmSender.memScriptDragDrop(Sender, Source: TObject; X,
2908   Y: Integer);
2909 var Src: TBottleLogDragObject;
2910     Log: TLogItem;
2911 begin
2912   // \83\8d\83O\83E\83B\83\93\83h\83E\82©\82ç\83\8d\83O\83A\83C\83e\83\80\82ðD&D\82µ\82Ä\82­\82é
2913   if not (Source is TBottleLogDragObject) then
2914     Exit;
2915   if (Source as TBottleLogDragObject).LogItem.LogType <> ltBottle then
2916     Exit;
2917   Src := Source as TBottleLogDragObject;
2918   Log := Src.LogItem;
2919   CopyFromLogToEditor(Log);
2920 end;
2921
2922 procedure TfrmSender.CopyFromLogToEditor(Log: TLogItem);
2923 begin
2924   if Log.LogType <> ltBottle then Exit;
2925   frmSender.actClear.Execute; // \8c»\8dÝ\82Ì\83X\83N\83\8a\83v\83g\82ð\83N\83\8a\83b\83v\82·\82é(\90Ý\92è\82É\82æ\82Á\82Ä)
2926   memScript.Lines.Clear;
2927   memScript.Lines.Add(Log.Script);
2928   if Log.Ghost <> '' then
2929   begin
2930     // \83S\81[\83X\83g\96¼\82ð\83{\83b\83N\83X\82É\93ü\82ê\82é
2931     // \96³\97\9d\96î\97\9d\83S\81[\83X\83g\96¼\82ð\92Ç\89Á\82µ\82Ä\82©\82ç\8dÄ\8d\\92z\82·\82é\82±\82Æ\82Å
2932     // \96³\97\9d\96î\97\9d\83S\81[\83X\83g\96¼\82ª\83{\83b\83N\83X\82É\93ü\82é
2933     cbxTargetGhost.Items.Add(Log.Ghost);
2934     cbxTargetGhost.ItemIndex := cbxTargetGhost.Items.Count-1;
2935     UpdateIfGhostBox;
2936     cbxTargetGhost.Invalidate;
2937   end else
2938     cbxTargetGhost.ItemIndex := 0; // 'CH\90\84\8f§'\82É\82·\82é
2939   memScript.SetFocus;
2940 end;
2941
2942 procedure TfrmSender.actDeleteLogItemExecute(Sender: TObject);
2943 begin
2944   // \83\8d\83O\83E\83B\83\93\83h\83E\82Ì\8cÂ\95Ê\83\8d\83O\82ð\8dí\8f\9c\82·\82é
2945   if frmLog.SelectedBottleLog = nil then
2946     Exit;
2947   if frmLog.lvwLog.Selected = nil then
2948     Exit;
2949   frmLog.SelectedBottleLog.Delete(frmLog.lvwLog.Selected.Index);
2950   frmLog.UpdateWindow;
2951   frmLog.lvwLogChange(Self, nil, ctState);
2952 end;
2953
2954 procedure TfrmSender.ClearEditor;
2955 var TmpScript: String;
2956     Position: Integer;
2957     DoSaveBuffer: boolean;
2958     SavedScript: TStringList;
2959 begin
2960   // \83X\83N\83\8a\83v\83g\82Ì\83N\83\8a\83A
2961   // \82Ü\82¸\81A\83X\83N\83\8a\83v\83g\83N\83\8a\83A\83o\83b\83t\83@\82É\8c»\8dÝ\82Ì\83X\83N\83\8a\83v\83g\82ð\95Û\91\82·\82é
2962   DoSaveBuffer := false;
2963   if FScriptBuffer.Count = 0 then
2964     DoSaveBuffer := true
2965   else if (FScriptBuffer[0] as TStringList).Text <> GetScriptText then
2966     DoSaveBuffer := true;
2967   if (GetScriptText = Pref.DefaultScript) or (GetScriptText = '') then
2968     DoSaveBuffer := false;
2969   if DoSaveBuffer then
2970   begin
2971     SavedScript := TStringList.Create;
2972     SavedScript.Text := GetScriptText;
2973     FScriptBuffer.Insert(0, SavedScript);
2974   end;
2975   if FScriptBuffer.Count >= 4 then
2976     FScriptBuffer.Delete(FScriptBuffer.Count-1);
2977   actRecallScriptBuffer.Enabled := FScriptBuffer.Count > 0;
2978
2979   TmpScript := Pref.DefaultScript;
2980   Position := Pos('|', TmpScript);
2981   if Position < 1 then Position := 1;
2982   TmpScript := StringReplace(TmpScript, '|', '', []);
2983   memScript.Lines.Text := TmpScript;
2984   Sendmessage(memScript.Handle, WM_VSCROLL, SB_LINEUP, 0);
2985   memScript.SelStart := Position-1;
2986
2987   if Visible then memScript.SetFocus;
2988   FScriptModified := false;
2989   memScriptChange(self);
2990 end;
2991
2992 procedure TfrmSender.AppendTextLog(const FileName, Line: String);
2993 var
2994   F: TextFile;
2995 begin
2996   //\91\97\90M\83\8d\83O\95Û\91
2997   try
2998     ForceDirectories(ExtractFileDir(FileName));
2999     AssignFile(F, FileName);
3000     if FileExists(FileName) then
3001       Append(F)
3002     else
3003       Rewrite(F);
3004     WriteLn(F, Line);
3005     Flush(F);
3006     CloseFile(F);
3007   except
3008     on E: Exception do
3009       frmLog.AddCurrentSystemLog('SYSTEM', '\83e\83L\83X\83g\83\8d\83O\95Û\91\82É\8e¸\94s\81F'+E.Message);
3010   end;
3011 end;
3012
3013 procedure TfrmSender.AppendXMLLog(const FileName: String; Args: THeadValue);
3014 var
3015   F: TFileStream;
3016   Buf: String;
3017   P: integer;
3018   Impl: TDomImplementation;
3019   Parser: TXmlToDomParser;
3020   DOM: TdomDocument;
3021 begin
3022   try // Long try block to handle all kinds of exception in this method
3023     if not FileExists(FileName) then
3024     begin
3025       // Create empty XML log file
3026       Impl := TDomImplementation.create(nil);
3027       try
3028         ForceDirectories(ExtractFileDir(FileName));
3029         Parser := TXmlToDomParser.create(nil);
3030         Parser.DOMImpl := Impl;
3031         try
3032           try
3033             DOM := Parser.fileToDom(ExtractFilePath(Application.ExeName)+'xbtl.dat');
3034             with DOM do
3035             begin
3036               documentElement.setAttribute('saved',
3037                 FormatDateTime('yy/mm/dd hh:nn:ss', Now));
3038               documentElement.setAttribute('generator', VersionString);
3039               documentElement.setAttribute('version', '1.0');
3040             end;
3041             // \82±\82ê\82Í\96¾\8e¦\93I\82ÉFree\82µ\82È\82­\82Ä\82æ\82¢
3042             F := TFileStream.Create(FileName, fmCreate or fmShareExclusive);
3043             try
3044               DOM.writeCodeAsShiftJIS(F);
3045             finally
3046               F.Free;
3047             end;
3048           except
3049             frmLog.AddCurrentSystemLog('SYSTEM', 'XML\83\8d\83O\95Û\91\82É\8e¸\94s\82µ\82Ü\82µ\82½');
3050           end;
3051         finally
3052           Parser.DOMImpl.freeDocument(DOM);
3053           Parser.Free;
3054         end;
3055       finally;
3056         Impl.Free;
3057       end;
3058     end;
3059     F := TFileStream.Create(FileName, fmOpenReadWrite or fmShareExclusive);
3060     try
3061       P := -11;
3062       SetLength(Buf, 12);
3063       while P > -100 do
3064       begin
3065         F.Seek(P, soFromEnd);
3066         F.Read(Buf[1], 12);
3067         if Buf = '</bottlelog>' then
3068           Break;
3069         Dec(P);
3070       end;
3071       if P = -100 then
3072         raise Exception.Create(FileName + ' is not a valid XML bottle log file')
3073       else
3074       begin
3075         F.Seek(P, soFromEnd);
3076         Buf := Format('<message mid="%s">', [Args['MID']]);
3077         Buf := Buf + Format('<date>%s</date>', [FormatDateTime('yy/mm/dd hh:nn:ss', Now)]);
3078         Buf := Buf + Format('<channel>%s</channel>', [XMLEntity(Args['Channel'])]);
3079         Buf := Buf + Format('<script>%s</script>', [XMLEntity(Args['Script'])]);
3080         Buf := Buf + '<votes>0</votes><agrees>0</agrees>';
3081         Buf := Buf + Format('<ghost>%s</ghost>', [XMLEntity(Args['IfGhost'])]);
3082         Buf := Buf + '</message>';
3083         Buf := Buf + '</bottlelog>';
3084         F.Write(Buf[1], Length(Buf));
3085       end;
3086     finally
3087       F.Free;
3088     end;
3089   except
3090     on E: Exception do
3091       frmLog.AddCurrentSystemLog('SYSTEM', 'XML\83\8d\83O\95Û\91\82É\8e¸\94s\82µ\82Ü\82µ\82½:'+E.Message);
3092   end;
3093 end;
3094
3095 procedure TfrmSender.memScriptSelectionChange(Sender: TObject;
3096   Selected: Boolean);
3097 var
3098   SelText: String;
3099 begin
3100   SelText := memScript.SelText;
3101   if SelText <> '' then
3102   begin
3103     StatusBar.Panels[PanelBytes].Text := Format('(%d\83o\83C\83g)', [Length(SelText)]);
3104   end else
3105   begin
3106     memScriptChange(Self);
3107   end; 
3108 end;
3109
3110 function TfrmSender.ReplaceSurface(Script: String;
3111   Params: TCollection): String;
3112 var
3113   Flag, OldLeaveEscape, OldEscapeInvalidMeta: boolean;
3114   OldStr, Tag: String;
3115   i, j, k, Cur: integer;
3116   Item: TSurfaceReplaceItem;
3117   Before: TSurfaceReplaceBeforeItem;
3118 begin
3119   Result := '';
3120   Cur := 0;
3121   with SsParser do
3122   begin
3123     OldStr := InputString;
3124     OldLeaveEscape := LeaveEscape;
3125     OldEscapeInvalidMeta := EscapeInvalidMeta;
3126     LeaveEscape := true;
3127     EscapeInvalidMeta := false;
3128     InputString := Script;
3129   end;
3130   for i := 0 to SsParser.Count-1 do
3131   begin
3132     if SsParser.MarkUpType[i] <> mtTag then
3133     begin
3134       Result := Result + SsParser.Str[i];
3135       Continue;
3136     end;
3137     Tag := SsParser.Str[i];
3138     if SsParser.Match(Tag, '\s%d') = 2 then
3139       Cur := Ord(Tag[3]) - Ord('0')
3140     else if SsParser.Match(Tag, '\s[%D]') > 0 then
3141       Cur := StrToInt(SsParser.GetParam(Tag, 1))
3142     else
3143     begin
3144       Result := Result + Tag;
3145       Continue;
3146     end;
3147     Flag := false;
3148     for j := 0 to Params.Count-1 do
3149     begin
3150       Item := Params.Items[j] as TSurfaceReplaceItem;
3151       for k := 0 to Item.Before.Count-1 do
3152       begin
3153         Before := Item.Before.Items[k] as TSurfaceReplaceBeforeItem;
3154         if (Cur >= Before.FromNo) and (Cur <= Before.ToNo) then
3155         begin
3156           Flag := true;
3157           Result := Result + Format('\s[%d]', [Item.After]);
3158           Break;
3159         end;
3160       end;
3161       if Flag then
3162         Break;
3163     end;
3164     if not Flag then
3165       Result := Result + Tag;
3166   end;
3167   with SsParser do
3168   begin
3169     LeaveEscape := OldLeaveEscape;
3170     EscapeInvalidMeta := OldEscapeInvalidMeta;
3171     InputString := OldStr;
3172   end;
3173 end;
3174
3175 procedure TfrmSender.WMQueryEndSession(var msg: TWMQueryEndSession);
3176 begin
3177   // Windows\82ª\8fI\97¹\82µ\82æ\82¤\82Æ\82µ\82Ä\82¢\82é\82Ì\82ð\8a´\92m\82·\82é
3178   FEndSession := true;
3179   inherited;
3180 end;
3181
3182 procedure TfrmSender.IdSLPP20ConnectFailed(Sender: TObject);
3183 begin
3184   Added := false;
3185   if FBeginConnectFailCount = 0 then
3186   begin
3187     Beep;
3188     if Pref.UseHttpProxy then
3189       ShowMessage('HTTP Proxy\82ð\92Ê\82\82ÄSSTP Bottle\83T\81[\83o\82É\90Ú\91±\82Å\82«\82Ü\82¹\82ñ\82Å\82µ\82½\81B'#13#10 +
3190                   '\83l\83b\83g\83\8f\81[\83N\82Ì\8fó\91Ô\81EProxy\82Ì\8fó\91Ô\82ð\8am\94F\82µ\82Ä\82­\82¾\82³\82¢\81B'#13#10 +
3191                   '\82 \82é\82¢\82Í\83T\81[\83o\82ª\83_\83E\83\93\82µ\82Ä\82¢\82é\89Â\94\\90«\82ª\82 \82è\82Ü\82·\81B')
3192     else
3193       ShowMessage('SSTP Bottle\83T\81[\83o\82É\90Ú\91±\82Å\82«\82Ü\82¹\82ñ\82Å\82µ\82½\81B'#13#10 +
3194                   '\83l\83b\83g\83\8f\81[\83N\82É\8cq\82ª\82Á\82Ä\82¢\82é\82©\8am\94F\82µ\82Ä\82­\82¾\82³\82¢\81B'#13#10 +
3195                   '\82 \82é\82¢\82Í\83T\81[\83o\82ª\83_\83E\83\93\82µ\82Ä\82¢\82é\89Â\94\\90«\82ª\82 \82è\82Ü\82·\81B');
3196   end;
3197   ShowHintLabel('SSTP Bottle Server\90Ú\91±\82É\8e¸\94s\82µ\82Ü\82µ\82½', WarningColor);
3198   Inc(FBeginConnectFailCount);
3199 end;
3200
3201 end.