-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
*.log | ||
*.ini | ||
~* | ||
*.zip | ||
*.dat | ||
*.csv | ||
# Lazarus compiler-generated binaries (safe to delete) | ||
*.exe | ||
*.dll | ||
*.so | ||
*.dylib | ||
*.res | ||
*.compiled | ||
*.dbg | ||
*.ppu | ||
*.o | ||
*.or | ||
*.a | ||
|
||
tgshd | ||
|
||
# Lazarus autogenerated files (duplicated info) | ||
*.rst | ||
*.rsj | ||
*.lrt | ||
|
||
# Lazarus local files (user-specific info) | ||
*.lps | ||
|
||
# Lazarus backups and unit output folders. | ||
# These can be changed by user in Lazarus/project options. | ||
backup/ | ||
*.bak | ||
lib/ | ||
|
||
# Application bundle for Mac OS | ||
*.app/ |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,3 +8,27 @@ Helps you work with your server (or remote computer) via telegram bot emulating | |
It is possible to work in the terminal from under any user in OS. You can configure access to several telegram users or only for You. | ||
|
||
The program can run as a regular console program or run as a daemon/service. | ||
|
||
Tested in Linux but You can try to use in other OS also. Developed with FreePascal. It depends on fp-telegram lib . | ||
|
||
1. Create bot https://core.telegram.org/bots/#3-how-do-i-create-a-bot . You must select longpolling method for getting updates. | ||
2. Create config ini file `telegram.ini` in app folder: | ||
|
||
``` INI | ||
[Bot] | ||
;; Specify Your token | ||
Token= | ||
|
||
[API] | ||
;; Actual if telegram server is blocked in server/computer region | ||
Endpoint=https://api.telegram.org/bot | ||
;; Timeout for lognpolling requests while getting updates | ||
Timeout=20 | ||
|
||
[Users] | ||
;; Specify all admin users (Telegram UserID [Integer]). For example: | ||
;;123456789=a | ||
YOUR_User_ID=a | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
Al-Muhandis
Author
Owner
|
||
``` | ||
|
||
3. Run as a console program or daemon/service. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
unit configuration; | ||
|
||
{$mode objfpc}{$H+} | ||
|
||
interface | ||
|
||
uses | ||
Classes, SysUtils, IniFiles; | ||
|
||
type | ||
TUserStatus = (usAdmin, usSimple, usBanned); // in future it can increase enums | ||
|
||
{ TConfig } | ||
|
||
TConfig = class | ||
private | ||
FIni: TMemIniFile; | ||
FUsers: TStringList; | ||
function GetAPIEndPoint: String; | ||
function GetAPITimeout: Integer; | ||
function GetBotTooken: String; | ||
function GetUsers(UserID: Int64): TUserStatus; | ||
function GetUserList: TStrings; | ||
public | ||
constructor Create(const AConfFile: String); | ||
destructor Destroy; override; | ||
property APIEndPoint: String read GetAPIEndPoint; | ||
property BotTooken: String read GetBotTooken; | ||
property Users[UserID: Int64]: TUserStatus read GetUsers; | ||
property APITimeout: Integer read GetAPITimeout; // longpolling timeout | ||
end; | ||
|
||
var | ||
Cnfg: TConfig; | ||
|
||
implementation | ||
|
||
uses | ||
tgsendertypes; | ||
|
||
var | ||
CnfDir: String; | ||
|
||
{ TConfig } | ||
|
||
function TConfig.GetAPIEndPoint: String; | ||
begin | ||
Result:=FIni.ReadString('API', 'Endpoint', TelegramAPI_URL); | ||
end; | ||
|
||
function TConfig.GetAPITimeout: Integer; | ||
begin | ||
Result:=FIni.ReadInteger('API', 'Timeout', 50); // 50 sec for longpolling request ?? | ||
end; | ||
|
||
function TConfig.GetBotTooken: String; | ||
begin | ||
Result:=FIni.ReadString('Bot', 'Token', EmptyStr) | ||
end; | ||
|
||
function TConfig.GetUsers(UserID: Int64): TUserStatus; | ||
var | ||
s: String; | ||
begin | ||
s:=GetUserList.Values[IntToStr(UserID)]; | ||
if s=EmptyStr then | ||
Exit(usSimple); | ||
case s[1] of | ||
'a': Result:=usAdmin; | ||
'b': Result:=usBanned; | ||
's': Result:=usSimple; | ||
else | ||
Result:=usSimple; | ||
end; | ||
end; | ||
|
||
function TConfig.GetUserList: TStrings; | ||
begin | ||
if not Assigned(FUsers) then | ||
begin | ||
FUsers:=TStringList.Create; | ||
FIni.ReadSectionRaw('users', FUsers); | ||
FUsers.Sorted:=True; | ||
end; | ||
Result:=FUsers; | ||
end; | ||
|
||
constructor TConfig.Create(const AConfFile: String); | ||
begin | ||
FIni:=TMemIniFile.Create(AConfFile); | ||
end; | ||
|
||
destructor TConfig.Destroy; | ||
begin | ||
FUsers.Free; | ||
FIni.Free; | ||
inherited Destroy; | ||
end; | ||
|
||
initialization | ||
CnfDir:=IncludeTrailingPathDelimiter(ExtractFileDir(ParamStr(0))); | ||
Cnfg:=TConfig.Create(CnfDir+'telegram.ini'); | ||
This comment has been minimized.
Sorry, something went wrong.
ashumkin
|
||
|
||
finalization | ||
FreeAndNil(Cnfg); | ||
|
||
end. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
unit shellthread; | ||
|
||
{$mode objfpc}{$H+} | ||
|
||
interface | ||
|
||
uses | ||
Classes, SysUtils, tgtypes, tgsendertypes, process, eventlog | ||
{$IFDEF MSWINDOWS}, Windows{$ENDIF} | ||
; | ||
|
||
type | ||
|
||
{ TShellThread } | ||
|
||
TShellThread=class(TThread) | ||
private | ||
FLogger: TEventLog; | ||
FBot: TTelegramSender; | ||
FProc: TProcess; | ||
FTerminated: Boolean; | ||
FLPTimeout: Integer; | ||
procedure BotReceiveMessage({%H-}ASender: TObject; AMessage: TTelegramMessageObj); | ||
procedure BotLogMessage({%H-}ASender: TObject; EventType: TEventType; const Msg: String); | ||
function GetLogger: TEventLog; | ||
procedure OutputStd; | ||
procedure SetLogger(AValue: TEventLog); | ||
property Logger: TEventLog read GetLogger write SetLogger; | ||
public | ||
constructor Create; | ||
destructor Destroy; override; | ||
procedure Execute; override; | ||
end; | ||
|
||
implementation | ||
|
||
uses | ||
configuration, tgshbot | ||
; | ||
|
||
{ TShellThread } | ||
|
||
procedure TShellThread.SetLogger(AValue: TEventLog); | ||
begin | ||
if FLogger=AValue then Exit; | ||
FLogger.Free; | ||
FLogger:=AValue; | ||
end; | ||
|
||
function TShellThread.GetLogger: TEventLog; | ||
begin | ||
if not Assigned(FLogger) then | ||
begin | ||
FLogger:=TEventLog.Create(nil); | ||
FLogger.Identification:='Shell thread'; | ||
end; | ||
Result:=FLogger; | ||
end; | ||
|
||
procedure TShellThread.BotReceiveMessage(ASender: TObject; | ||
AMessage: TTelegramMessageObj); | ||
var | ||
InputString: String; | ||
begin | ||
if FBot.CurrentIsSimpleUser then | ||
begin | ||
FBot.sendMessage('You cannot access to this bot!'); | ||
Exit; | ||
end; | ||
InputString:=AMessage.Text; | ||
if InputString=EmptyStr then | ||
Exit; | ||
InputString+=LineEnding; | ||
if FProc.Running then | ||
begin | ||
OutputStd; | ||
FProc.Input.Write(InputString[1], Length(InputString)); | ||
sleep(50); | ||
OutputStd; | ||
end; | ||
end; | ||
|
||
procedure TShellThread.BotLogMessage(ASender: TObject; EventType: TEventType; | ||
const Msg: String); | ||
begin | ||
Logger.Log(EventType, Msg); | ||
end; | ||
|
||
procedure TShellThread.OutputStd; | ||
var | ||
CharBuffer: array [0..511] of char; | ||
ReadCount: integer; | ||
OutputString: String; | ||
begin | ||
OutputString:=EmptyStr; | ||
while FProc.Output.NumBytesAvailable > 0 do | ||
begin | ||
ReadCount := FProc.Output.NumBytesAvailable; | ||
if ReadCount>Length(CharBuffer) then | ||
ReadCount:=Length(CharBuffer); | ||
FProc.Output.Read(CharBuffer{%H-}, ReadCount); | ||
OutputString+=Copy(CharBuffer, 0, ReadCount); | ||
// Write(StdOut, OutputString); // You can uncomment for debug | ||
end; | ||
if OutputString<>EmptyStr then | ||
FBot.sendMessage('```bash'+LineEnding+OutputString+LineEnding+'```', pmMarkdown); | ||
// read stderr and write to our stderr ... crashing :(( | ||
{ while FProc.Stderr.NumBytesAvailable > 0 do | ||
begin | ||
ReadCount := Min(512, FProc.Stderr.NumBytesAvailable); | ||
FProc.Stderr.Read(CharBuffer, ReadCount); | ||
FBot.sendMessage(Copy(CharBuffer, 0, ReadCount)); | ||
// Write(StdErr, Copy(CharBuffer, 0, ReadCount)); | ||
end; } | ||
end; | ||
|
||
constructor TShellThread.Create; | ||
begin | ||
inherited Create(True); | ||
FreeOnTerminate:=False; | ||
TelegramAPI_URL:=Cnfg.APIEndPoint; // For Russian specific case | ||
FBot:=TTgShBot.Create(Cnfg.BotTooken); | ||
if FBot.Token=EmptyStr then | ||
begin | ||
Logger.Error('Please, specify bot token in telegram.ini!'); | ||
Exit; | ||
end; | ||
FBot.OnReceiveMessage:=@BotReceiveMessage; | ||
FBot.OnLogMessage:=@BotLogMessage; | ||
{$IFDEF MSWINDOWS} | ||
SetConsoleOutputCP(CP_UTF8);{$ENDIF} | ||
FProc:=TProcess.Create(nil); | ||
FProc.Options := [poUsePipes, poStderrToOutPut]; | ||
FProc.Executable:={$IFDEF MSWINDOWS}'cmd'{$ELSE}'sh'{$ENDIF}; | ||
FProc.Execute; | ||
sleep(50); | ||
OutputStd; | ||
FTerminated:=False; | ||
FLPTimeout:=Cnfg.APITimeout; | ||
end; | ||
|
||
destructor TShellThread.Destroy; | ||
begin | ||
FreeAndNil(FProc); | ||
FreeAndNil(FBot); | ||
inherited Destroy; | ||
end; | ||
|
||
procedure TShellThread.Execute; | ||
begin | ||
while not Terminated do | ||
FBot.getUpdatesEx(0, FLPTimeout); | ||
end; | ||
|
||
end. | ||
|
Why cryptic roles (a, b, s)? Is not it more intuitive to use
admin
,ban/banned
,user
?