OSDN Git Service

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