the inky void
37 subscribers
20 photos
3 videos
24 links
deranged mamblings of a madman
Download Telegram
telegram-cli is the worst command line tool that I am aware of.

What I wanted: a simple shell command to write a message and send a file through telegram, given nickname and msg/file.
What I got: a lot of suffering and pain.

Starting the app, you get promted with your number, then the code you were sent and that works fine. You might get your dialog_list, send a couple message message through msg and that works fine too.

You might think that now you can simply just use the -e option to send a message in a shell command, but no, than doesn't work. replacing nickname with @username doesn't work either. Why so? Well, you can't just send messages to anyone, only those from dialog_list. This excellent architectural decision also means you can't start a new dialog with telegram-cli. The -e executes a single command before exiting, so you can't add dialog_list to the very beginning.

Maybe use the lua api? Two problems: it doesn't forward argv (it does forward stdin though so it's easy to just send arguments as zero terminated strings) and every function just fails abd, perhaps it was went to used with the daemon, but thats not clearly stated in the docs.

As it turns there is an option (-W) to send dialog_list, wait for it to output and then execute whatever, so I used that.

But the pain never doesn't end here. Remember how I said some things worked fine? Thats not entirely true, because sometimes dialog_list randomly fails with an assertion error and on macos that happens always, this can be fixed by restarting and rebooting sometimes. It also crashes if you don't have internet and with some filenames. The golden standart of stability and reliability.

Another issue is with spaces in filenames, they can't be opened, if qouted. The solution here isn't immediatly, so its necessary to inspect the sources (which require a 32-bit compiler to make for some reason, so it can't be compiled on macos, because it doesn't support 32-bit binaries anymore). telegram-cli depends on a lib called tgl (as I understand it was initially written by the author of telegram-cli, forked and then developed some more). In this excellent library tgl_do_send_document calls _tgl_do_send_photo to send any document, so you know its good. Its poorly documented c code with far too little abstractions and a terrible architecture. Public functions can take easily take 10+ arguments, the few comments that are there are either pointless statements for some automated system (like /* {{{ Profile name */ and /* }}} */), out-of-context note to self or commented out peaces of code, there are lines of code longer than 350 characters, structures are build by hand, rather than in functions. Anyway what source of the problem is in the aforementioned _tgl_do_send_photo, which calls wordexp(3) and uses the first word in we_wordv as the filename presumably to expand ~ -> $HOME, so of course if there is a space in a filename, it will split it into 2 words. A lib of course shouldn't expand ~, that should be done by the client application, but there is a simple a way to fix this. Just put the name in double qoutes with backslashes, like '\'file name\''. And yes, it does have tests, the are 68 and 126 lines long.
Some interesting behaviour in python, you might accidentally notice, is:
>>> class A:
... def m(self): ...
...
>>> a, b = A(), A()
>>> a.m == b.m
False
>>> a.m is b.m
False
>>> id(a.m) == id(b.m)
True
At first you might think you're being tricked and id just doesn't actually return a unique identifier, but no id just returns the address of the argument object:
https://github.com/python/cpython/blob/00d7abd7ef588fc4ff0571c8579ab4aba8ada1c0/Python/bltinmodule.c#L1170
Indeed debugging shows that the address of a.method is the address of b.method, but they're different objects, even on the memory level tp_self is different in them. How come? There's only one scenario where this could happen: if python binds methods on each access, not on object creation (python creates a.method, gets its id, then destroys it because it has 0 references, then creates b.method at the same address), which turns out to be the truth.
https://github.com/python/cpython/blob/master/Objects/object.c#L1155
Extremely readable code like all of the cpython codebase, but basically what it does is tries to get a method from the type (and mro), if it succeeds and it is a property it binds it and returns it straightaway, if not it gets the dict of obj and searches for the attribute there, returns it if found or if there is not such attribute, but it found a method earlier it binds it and returns it and else it found nothing it raises AttributeError. Thats why you can overwrite methods (and get them back by deleting attributes) it also means you can do stuff like this:
>>> class A:
... def a(self): print("a")
...
>>> a = A()
>>> a.a()
a
>>> A.a = lambda self: print("b")
>>> a.a()
b
>>> A.c = lambda self: print("c")
>>> a.c()
c
>>> m1, m2 = a.a, a.a
>>> id(m1), id(m2)
(140043233937072, 140043239244336)
>>> id(m1) == id(m2)
False
Why? I don't know, I guess maybe you'd want to change the class or its mro is some bizarre world.
People still ask why python is slow, this is why. While php introduces jit in new version, python binds methods at each access.
Some time ago I came across a riddle. What do you think will the following code do?
#include <bits/stdc++.h>
using namespace std;

int ost[] = {0, 1, 2, 3, 4, 5, 6};

int main()
{
for(int i = 0, val = ost[0]; i < 7; val = ost[++i]){
cout << val << endl;
}

return 0;
}
a) print numbers from 0 to 7
b) print numbers from 0 to 7
c) print numbers from 0 to 7
d) print random stuff and the segfault

a|b|c are indeed correct, if you don't compile it with optimizations, but if you do it will indeed crash. The reason why is pretty interesting and took me a while to figure out: basically the last call to operator<< in cout << val << endl is inlined and has a potential throw in its small code, val = ost[++i] is undefined behavior for i = 6 and should not be reached, meaning for the compiler the loop always breaks before the last element is reached, it assumes that the exit is the aforementioned raise and optimizes the loop condition out, as well as putting the throw after the loop and replacing the call with a break.

This behaviour can be reproduced in both c and c++ by replacing cout << val << endl with any function call that will be inlined and can throw exit from the program and any usage of ost (so that the array access is not optimized out), however it is a lot less likely in c (the highest chance for it to show up is near user redefined memory allocations which exit if malloc fails), For a synthetic example
#include <bits/stdc++.h>
using namespace std;

int ost[] = {0, 1, 2, 3, 4, 5, 6};

void mb_exit(int n) {
if (rand() == 1337 + n) {
exit(1337);
}
}

int main()
{
for(int i = 0, val = ost[0]; i < 7; val = ost[++i]){
mb_exit(val);
}

return 0;
}
lol gcc allows (clang doesn't as "this is a complex feature which is infrequently used, so it is unlikely to be implemented anytime soon") to allocate closures on the stack, automatically disabling nx and making the stack executable. Very cool idea that fits into c semantics perfectly. Unfortunately it's too late to build security technologies around it so I doubt it will ever see much use, let alone replace int (*f) (void *, ...), void *arg. All it does is absolutely (ie not via call, but via a constant and register) call the underling function with the pointer to a part of the stack with the closure variables in a register not used by the calling convention.
1 typedef int (*func)(int);
2
3 void make_closure(int n) {
4 int closure(int m) { return n + m; }
5 func f = &closure;
→ 6 }
7
8 int main() {
9 make_closure(1337);
10 }
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── threads ────
[#0] Id 1, Name: "a.out", stopped 0x5555555551b1 in make_closure (), reason: SINGLE STEP
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── trace ────
[#0] 0x5555555551b1 → make_closure(n=0x539)
[#1] 0x5555555551d6 → main()
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
gef➤ x/3i f
0x7fffffffe0d4: movabs r11,0x555555555139
0x7fffffffe0de: movabs r10,0x7fffffffe0d0
0x7fffffffe0e8: rex.WB jmp r11
gef➤ x/10i 0x555555555139
0x555555555139 <closure>: push rbp
0x55555555513a <closure+1>: mov rbp,rsp
0x55555555513d <closure+4>: mov DWORD PTR [rbp-0x4],edi
0x555555555140 <closure+7>: mov rax,r10
0x555555555143 <closure+10>: mov QWORD PTR [rbp-0x10],r10
0x555555555147 <closure+14>: mov edx,DWORD PTR [rax]
0x555555555149 <closure+16>: mov eax,DWORD PTR [rbp-0x4]
0x55555555514c <closure+19>: add eax,edx
0x55555555514e <closure+21>: pop rbp
0x55555555514f <closure+22>: ret
the time has come again for me to create a channel. I have recovered most of the old posts, but this time it will be a little bit different. i will try to consistently provide some meaningful content, but with more leeway for short snippets of information, thoughts and mostly music.
the inky void pinned «the time has come again for me to create a channel. I have recovered most of the old posts, but this time it will be a little bit different. i will try to consistently provide some meaningful content, but with more leeway for short snippets of information…»
пон
thanks for the suggestion
haven't seen that in a looooong time
👍2
а из моего окна площадь красная не видна...
🤔5😢4
> men enjoy the goth girl aesthetic because it represents a woman that is externally consistent with her inner state. that is to say - evil
🔥2
настроение вспомнить детство