forked from sloum/gab2
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
356 lines
11 KiB
356 lines
11 KiB
#!/usr/bin/env python3
|
|
import os
|
|
import sys
|
|
import time
|
|
from datetime import datetime
|
|
import subprocess as sp
|
|
from subprocess import call
|
|
import tempfile
|
|
|
|
LIST_MESSAGES_LIMIT = "5"
|
|
|
|
chan_dir = ".config/gab/channels" ## not used yet. todo: move all gab channel logs to this dir
|
|
current_user = os.environ.get('USER')
|
|
log = {}
|
|
|
|
help_text = """
|
|
GAB - A simple chat interface
|
|
|
|
syntax: gab [flag] [value]
|
|
|
|
flag value
|
|
-------------------- ---------------
|
|
-h, --help, help
|
|
-m, --msg, msg Quoted text with the msg being added to chat
|
|
-l, --list, list An integer representing the number of rows you'd like
|
|
to view, default 5
|
|
-b, --block, block A username to block/ignore
|
|
-u, --unblock, unblock A username to unblock/unignore
|
|
-c, --channel, channel Name of the channel you would like to join or create.
|
|
An empty value lists the available channels.
|
|
-n, --new, new Check for new, unread messages.
|
|
-N, --new-verbose, new-verbose Check for new, unread messages, creating output
|
|
even when no new messages exist.
|
|
|
|
Channels names ending in ! are private. They can be joined by anyone that
|
|
knows they exist, but will not be listed in the channel listings. To return
|
|
to the main/default channel, simply switch channels to 'gab':
|
|
gab channel gab
|
|
|
|
Examples:
|
|
gab msg "Good afternoon!"
|
|
gab list 20
|
|
gab block annoyingperson
|
|
gab channel my-secret-channel!
|
|
gab channel a-public-channel
|
|
gab unblock somedude
|
|
"""
|
|
|
|
title = "\033[1mGAB v2.2\033[0m"
|
|
|
|
def get_chan():
|
|
fp = "/home/{}/.gab_chan".format(current_user)
|
|
|
|
if not os.path.isfile(fp):
|
|
return ""
|
|
|
|
with open(fp, 'r') as chanfile:
|
|
channel = chanfile.read().split("\n")[0].strip()
|
|
if channel:
|
|
channel = "-" + channel
|
|
return channel
|
|
|
|
def blocked_users():
|
|
fp = "/home/{}/.gab_block".format(current_user)
|
|
|
|
if not os.path.isfile(fp):
|
|
return []
|
|
|
|
with open(fp, 'r') as blockfile:
|
|
return blockfile.read().split("\n")
|
|
|
|
def get_files(channel):
|
|
return [[x, "/home/{}/.gab{}".format(x, channel)] for x in os.listdir("/home/") if x not in blocked_users() and os.access("/home/"+x, os.R_OK)]
|
|
|
|
|
|
def get_user_channels(user_dir):
|
|
chans = {"gab"}
|
|
for y in os.listdir(user_dir):
|
|
if len(y) > 5 and y[:5] == ".gab-" and y[-1] != "!":
|
|
chans.add(y[5:])
|
|
return chans
|
|
|
|
|
|
def get_chan_list():
|
|
chans = {"gab"}
|
|
for x in os.listdir("/home/"):
|
|
for y in os.listdir("/home/" + x):
|
|
if len(y) > 5 and y[:5] == ".gab-" and y[-1] != "!":
|
|
chans.add(y[5:])
|
|
return chans
|
|
|
|
|
|
def list_channels():
|
|
chans = get_chan_list()
|
|
chan = get_chan()
|
|
print(title)
|
|
print("\n\033[1mAvailable channels\033[0m:")
|
|
for x in chans:
|
|
if chan[1:] == x:
|
|
x = x + " *"
|
|
elif chan == "" and x == "gab":
|
|
x = x + " *"
|
|
print(x)
|
|
|
|
|
|
def read_file(user, path, num_lines):
|
|
global log
|
|
if os.path.isfile(path) and os.access(path, os.R_OK):
|
|
if "/home/" + current_user + "/" in path:
|
|
os.utime(path, None) ## update file's timestamp on each read
|
|
with open(path, "r") as f:
|
|
for line in range(num_lines):
|
|
msg = f.readline().split("|", 1)
|
|
dt = msg[0].strip()
|
|
if len(msg) == 2 and float(dt) < time.time():
|
|
msg = msg[1].strip()
|
|
if msg[:3] == "/me":
|
|
log[dt] = "\033[7m * * * \033[0m \033[3m{}\033[0m".format(msg.replace("/me", user))
|
|
else:
|
|
log[dt] = "\033[7m {} \033[0m {}\033[0m".format(user, msg)
|
|
|
|
|
|
def list_messages(count=LIST_MESSAGES_LIMIT):
|
|
global log
|
|
chan = get_chan()
|
|
files = get_files(chan)
|
|
|
|
try:
|
|
count = int(count)
|
|
except ValueError:
|
|
print("Error parsing list number, using default: 5")
|
|
count = 5
|
|
|
|
for x in files:
|
|
read_file(x[0], x[1], count)
|
|
|
|
sorted_keys = list(log.keys())
|
|
if len(sorted_keys) > 0:
|
|
sorted_keys.sort(reverse=True)
|
|
last_time = float(sorted_keys[0])
|
|
sorted_keys = sorted_keys[:min(len(sorted_keys), count)]
|
|
sorted_keys.sort(reverse=False)
|
|
print(title)
|
|
print("Current channel: \033[1m{}\033[0m".format(chan[1:] if chan else "gab"))
|
|
print("Last message: {}".format(diff_time_from_now(last_time)))
|
|
print("\n- - -")
|
|
for key in range(min(count, len(sorted_keys))):
|
|
print(log[sorted_keys[key]])
|
|
print("- - -")
|
|
else:
|
|
print(title)
|
|
print("Current channel: \033[1m{}\033[0m".format(chan[1:] if chan else "gab"))
|
|
print()
|
|
print("There are no messages to display")
|
|
|
|
|
|
def diff_time_from_now(t, n=time.time()):
|
|
diff = n - t
|
|
diff = int(diff)
|
|
out = ""
|
|
|
|
# Days
|
|
if diff // (3600 * 24) > 0:
|
|
days = diff // (3600 * 24)
|
|
out += "{}d ".format(days)
|
|
diff = diff - (days * 3600 * 24)
|
|
|
|
# Hours
|
|
if diff // 3600 > 0:
|
|
out += "{}h ".format(diff // 3600)
|
|
diff = diff - (diff // 3600 * 3600)
|
|
|
|
# Minutes
|
|
if diff // 60 > 0:
|
|
out += "{}m ".format(diff // 60)
|
|
diff = diff - (diff // 60 * 60)
|
|
|
|
# Seconds
|
|
out += "{}s ago".format(diff)
|
|
|
|
return out
|
|
|
|
|
|
def add_message(msg):
|
|
timestamp = str(time.time())
|
|
output = "{}|{}\n".format(timestamp, msg.strip())
|
|
fp = "/home/{}/.gab{}".format(current_user, get_chan())
|
|
try:
|
|
with open(fp, 'r') as original:
|
|
data = original.read(12000)
|
|
with open(fp, 'w') as modified:
|
|
modified.write(output)
|
|
modified.write(data)
|
|
except FileNotFoundError:
|
|
with open(fp, 'a') as modified:
|
|
modified.write(output)
|
|
except:
|
|
print("Error adding text to chatlog")
|
|
return
|
|
|
|
print("Successfully added text to chatlog")
|
|
|
|
try:
|
|
os.chmod(fp, 0o644)
|
|
except PermissionError:
|
|
print("You do not have permission to modify the chatlog")
|
|
except FileNotFoundError:
|
|
print("The chatlog does not exist")
|
|
|
|
|
|
def block_user(user_to_block):
|
|
fp = "/home/{}/.gab_block".format(current_user)
|
|
block_fp = "/home/{}/".format(user_to_block)
|
|
if not os.path.isdir(block_fp):
|
|
print("User '{}' does not exist, no action taken".format(user_to_block))
|
|
return
|
|
|
|
with open(fp, 'a') as blockfile:
|
|
blockfile.write(user_to_block)
|
|
blockfile.write("\n")
|
|
|
|
print("User '{}' has been blocked, you will not see their messages".format(user_to_block))
|
|
return
|
|
|
|
|
|
def unblock_user(user_to_unblock):
|
|
fp = "/home/{}/.gab_block".format(current_user)
|
|
unblock_fp = "/home/{}/".format(user_to_unblock)
|
|
|
|
if not os.path.isfile(fp):
|
|
print("You do not have any users on your block list, no action taken")
|
|
return
|
|
|
|
if not os.path.isdir(unblock_fp):
|
|
print("User '{}' does not exist, no action taken".format(user_to_unblock))
|
|
return
|
|
|
|
blocked_users_list = [x for x in blocked_users() if x != user_to_unblock]
|
|
|
|
with open(fp, 'w') as blocked:
|
|
blocked.write("\n".join(blocked_users_list))
|
|
|
|
print("User '{}' has been removed from your block list".format(user_to_unblock))
|
|
|
|
|
|
def switch_channel(newchan):
|
|
chan = newchan
|
|
if newchan == "gab":
|
|
newchan = ""
|
|
|
|
fp = "/home/{}/.gab_chan".format(current_user)
|
|
|
|
with open(fp, 'w') as chanfile:
|
|
chanfile.write(newchan)
|
|
|
|
print("You are now viewing the '{}' channel.".format(chan))
|
|
list_messages()
|
|
|
|
|
|
def new_scan(silent=True):
|
|
unread_chans = []
|
|
chans = get_user_channels("/home/" + current_user)
|
|
|
|
for c in chans:
|
|
my_timestamp = chan_timestamp = 0.0
|
|
if c == "gab":
|
|
files = get_files("")
|
|
else:
|
|
files = get_files("-" + c)
|
|
|
|
for f in files:
|
|
if os.path.isfile(f[1]):
|
|
with open(f[1]) as fh:
|
|
try:
|
|
timestamp = float(fh.readline().split("|")[0])
|
|
if timestamp > float(chan_timestamp):
|
|
chan_timestamp = timestamp
|
|
if f[0] == current_user:
|
|
atime= time.ctime(os.stat(f[1]).st_atime)
|
|
my_timestamp = time.mktime(datetime.strptime(atime, "%a %b %d %H:%M:%S %Y").timetuple())
|
|
except:
|
|
continue
|
|
if my_timestamp - chan_timestamp < 0:
|
|
unread_chans.append(c)
|
|
|
|
if len(unread_chans):
|
|
print("New gab messages in: " + ", ".join(unread_chans))
|
|
else:
|
|
if silent == False:
|
|
print("gab: no unread messages.")
|
|
exit(1)
|
|
|
|
|
|
def parse_command():
|
|
args = sys.argv[1:]
|
|
if not len(args):
|
|
list_messages()
|
|
elif args[0] in ["-h", "--help", "help"]:
|
|
print(help_text)
|
|
elif args[0] in ["list", "--list", "-l"]:
|
|
if len(args) == 2:
|
|
list_messages(args[1])
|
|
else:
|
|
print("Invalid command input to 'list'")
|
|
elif args[0] in ["new", "--new", "-n"]:
|
|
new_scan()
|
|
elif args[0] in ["new-verbose", "--new-verbose", "-N"]:
|
|
new_scan(silent=False)
|
|
elif args[0] in ["-m", "--msg", "msg"]:
|
|
if len(args) < 2:
|
|
# code from https://stackoverflow.com/a/6309753
|
|
EDITOR = os.environ.get('EDITOR') if os.environ.get('EDITOR') else 'vi'
|
|
with tempfile.NamedTemporaryFile(suffix=".tmp") as tf:
|
|
tf.flush()
|
|
call([EDITOR, tf.name])
|
|
tf.seek(0)
|
|
edited_message = tf.read()
|
|
lines = edited_message.decode("utf-8").split("\n")
|
|
for line in lines:
|
|
if len(line.split()):
|
|
add_message(line)
|
|
|
|
elif len(args) > 2:
|
|
print("Expected a message, but received too many arguments. Did you put your message in quotes?")
|
|
else:
|
|
add_message(args[1])
|
|
elif args[0] in ["-b", "--block", "block"]:
|
|
if len(args) < 2:
|
|
print("Expected a user to block, but one was not received")
|
|
elif len(args) > 2:
|
|
print("Expected a user to block, but received too many arguments")
|
|
else:
|
|
block_user(args[1])
|
|
elif args[0] in ["-u", "--unblock", "unblock"]:
|
|
if len(args) < 2:
|
|
print("Expected a user to unblock, but one was not received")
|
|
elif len(args) > 2:
|
|
print("Expected a user to unblock, but received too many arguments")
|
|
else:
|
|
unblock_user(args[1])
|
|
elif args[0] in ["-c", "--channel", "channel"]:
|
|
if len(args) < 2:
|
|
# print("Returning to default channel.")
|
|
# switch_channel("gab")
|
|
list_channels()
|
|
elif len(args) > 2:
|
|
print("Expected a channel to join, but received too many arguments")
|
|
else:
|
|
switch_channel(args[1])
|
|
else:
|
|
print("Unknown command: {}".format(args[0]))
|
|
|
|
|
|
if __name__ == '__main__':
|
|
parse_command()
|