Merge remote-tracking branch 'upstream/develop'

This commit is contained in:
Paul Henry 2018-12-08 21:23:46 -05:00
commit 6e64d3adc1
No known key found for this signature in database
GPG Key ID: B4106EC304DE6275
6 changed files with 123 additions and 44 deletions

1
.gitignore vendored
View File

@ -2,3 +2,4 @@ __pycache__/*
__pycache__
*.swp
*.json
*.pyc

2
burrow.py → burrow Normal file → Executable file
View File

@ -2,7 +2,7 @@
################################################
## Burrow, a gopher client/browser
## - - - - - - - - - - - - - - - - - - - - - - -
## Version 0.2.1
## Version 0.8.8
################################################
from gui import GUI

View File

@ -8,16 +8,19 @@ class connect:
def request(self, resource, host, itemtype, port=70):
#connects to server and returns list with response type and body
socket_conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket_conn.settimeout(5.0)
socket_conn.settimeout(15.0)
try:
socket_conn.connect((host, port))
socket_conn.sendall((resource + '\r\n').encode('utf-8'))
if itemtype in ['I','p','g']:
response = socket_conn.makefile(mode = 'rb', errors = 'ignore')
else:
if itemtype in ['i','0','1','3']:
response = socket_conn.makefile(mode = 'r', errors = 'ignore')
else:
response = socket_conn.makefile(mode = 'rb', errors = 'ignore')
self.raw_response = response.read()
self.filetype = itemtype
except socket.timeout:
print('Socket timeout')
socket_conn.close()
@ -27,13 +30,6 @@ class connect:
socket_conn.close()
return {'type': '1', 'body': '3ERROR: Unable to communicate with remote server\tfalse\tnull.host\t1'}
try:
self.raw_response = response.read()
self.filetype = itemtype
except UnicodeDecodeError:
self.raw_response = '3ERROR: Unable to decode server response\tfalse\tnull.host\t1'
self.filetype = '3'
socket_conn.close()
return {'type': self.filetype, 'body': self.raw_response}

135
gui.py
View File

@ -2,6 +2,7 @@
import tkinter as tk
import tkinter.simpledialog as dialog
from tkinter.filedialog import asksaveasfilename as savedialog
from connect import connect as conn
from parser import parser
import time
@ -17,7 +18,6 @@ class GUI:
self.history = []
self.history_location = -1
self.message_bar_content = ''
# self.config = None
self.read_config()
self.conn = conn()
self.parser = parser()
@ -46,7 +46,7 @@ class GUI:
self.MENU_HLB = self.LINK
self.MENU_HLF = self.BAR_BG
#create and configure root window
#configure root window
self.root = tk.Tk(className='Burrow')
self.root.title('Burrow')
sh = self.root.winfo_screenheight()
@ -71,7 +71,7 @@ class GUI:
#body objects
self.scroll_bar = tk.Scrollbar(self.body, bg=self.BAR_BG, bd=0, highlightthickness=0, troughcolor=self.BG, activebackground=self.SCROLL, activerelief=tk.RAISED)
self.site_display = tk.Text(self.body, bg=self.BG, foreground=self.FG, padx=20, pady=20, wrap=tk.WORD, state=tk.DISABLED, spacing2=2, spacing1=2, spacing3=2, yscrollcommand=self.scroll_bar.set, highlightcolor=self.BG, highlightbackground=self.BAR_BG, relief=tk.FLAT)
self.site_display = tk.Text(self.body, bg=self.BG, foreground=self.FG, padx=20, pady=20, wrap=tk.WORD, state=tk.DISABLED, spacing2=2, spacing1=2, spacing3=2, yscrollcommand=self.scroll_bar.set, highlightcolor=self.BG, highlightbackground=self.BAR_BG, relief=tk.FLAT, font="TkFixedFont")
self.scroll_bar.config(command=self.site_display.yview, width=20, relief=tk.RIDGE)
self.site_display.tag_configure('linkcolor', foreground=self.LINK, spacing1=5, spacing2=5, spacing3=5)
self.site_display.tag_configure('favoritecolor', foreground=self.FLINK, spacing1=5, spacing2=5, spacing3=5)
@ -85,7 +85,6 @@ class GUI:
#menu objects
self.context_menu = tk.Menu(self.body, tearoff=0, bg=self.MENU_BG, fg=self.MENU_FG, activebackground=self.MENU_HLB, activeforeground=self.MENU_HLF, activeborderwidth=0)
self.pack_geometry()
self.add_status_titles()
self.add_event_listeners()
@ -93,8 +92,10 @@ class GUI:
#load the home screen
self.load_home_screen(1)
#-----------Start GUI configuration-----------------------
def add_event_listeners(self):
buttons = [
self.btn_back,
@ -121,7 +122,6 @@ class GUI:
self.site_display.tag_bind('generic_r_click', "<Button-3>", (lambda event, href=None: self.show_context_menu(event, href)))
def pack_geometry(self):
self.top_bar.pack(expand=False,fill=tk.BOTH,side=tk.TOP,anchor=tk.NW)
self.top_bar.pack_propagate(False)
@ -147,42 +147,67 @@ class GUI:
def add_assets(self):
<<<<<<< HEAD
self.img_back = tk.PhotoImage(file='./images/back.gif')
self.img_forward = tk.PhotoImage(file='./images/forward.gif')
self.img_favorite = tk.PhotoImage(file='./images/favorite.gif')
self.img_home = tk.PhotoImage(file='./images/home.gif')
self.img_menu = tk.PhotoImage(file='./images/settings.gif')
=======
back = Image.open('./images/back.png')
self.img_back = ImageTk.PhotoImage(back)
forward = Image.open('./images/forward.png')
self.img_forward = ImageTk.PhotoImage(forward)
favorite = Image.open('./images/favorite.png')
self.img_favorite = ImageTk.PhotoImage(favorite)
home = Image.open('./images/home.png')
self.img_home = ImageTk.PhotoImage(home)
settings = Image.open('./images/settings.png')
self.img_menu = ImageTk.PhotoImage(settings)
>>>>>>> upstream/develop
self.message_bar_content = tk.StringVar()
self.message_bar_content.set('Ready.')
def show_context_menu(self, e, href=None):
current_page = self.entry_url.get()
self.context_menu.delete(0,20)
#add navigation options
if len(self.history) > 1 or self.history_location > 0:
if len(self.history) > 1 and self.history_location > 0:
back = (lambda event=e: self.go_back(event))
self.context_menu.add_command(label="Back", command=back)
if len(self.history) > 1 or self.history_location < len(self.history) - 2:
self.context_menu.add_command(label=" Back ", command=back)
else:
self.context_menu.add_command(label=" Back ", state=tk.DISABLED)
if len(self.history) > 1 and self.history_location < len(self.history) - 1:
forward = (lambda event=e: self.go_forward(event))
self.context_menu.add_command(label="Forward", command=forward)
if self.entry_url.get() != 'home':
self.context_menu.add_command(label=" Forward ", command=forward)
else:
self.context_menu.add_command(label=" Forward ", state=tk.DISABLED)
refresh = (lambda event=e, link=current_page: self.handle_request(event, link, False))
self.context_menu.add_command(label=" Refresh ", command=refresh)
if current_page != 'home':
home = (lambda event=e: self.load_home_screen(event))
self.context_menu.add_command(label="Home", command=home)
self.context_menu.add_command(label=" Home ", command=home)
else:
self.context_menu.add_command(label=" Home ", state=tk.DISABLED)
save_as_file = (lambda data=self.site_display.get(1.0,tk.END), url=current_page: self.write_to_file(data, url))
self.context_menu.add_command(label=" Save as... ", command=save_as_file)
if href:
copy_link = (lambda link=href: self.copy_to_clipboard(link))
self.context_menu.add_command(label="Copy URL to clipboard", command=copy_link)
self.context_menu.add_separator()
copy_link = (lambda link=href: self.copy_to_clipboard(link))
self.context_menu.add_command(label=" Copy URL to clipboard ", command=copy_link)
if self.is_favorite(href):
self.context_menu.add_separator()
delete_favorite = (lambda event=e, link=href: self.remove_favorite(event, link))
self.context_menu.add_command(label="Delete from favorites", command=delete_favorite)
self.context_menu.add_command(label=" Delete from favorites ", command=delete_favorite)
rename_favorite = (lambda event=e, link=href: self.rename_favorite(event, link))
self.context_menu.add_command(label="Rename this favorite", command=rename_favorite)
self.context_menu.add_command(label=" Rename this favorite ", command=rename_favorite)
elif href:
self.context_menu.add_separator()
add_favorite = (lambda event=e, link=href: self.add_to_favorites(event, link))
self.context_menu.add_command(label="Add to favorites", command=add_favorite)
self.context_menu.add_command(label=" Add to favorites ", command=add_favorite)
self.context_menu.tk_popup(e.x_root, e.y_root)
@ -191,7 +216,8 @@ class GUI:
self.root.clipboard_append(text)
# ------------Start navigation methods----------------------------
# ------------Start navigation methods---------------------------
def handle_request(self,event=False, url=False, history=True):
self.loading_bar = tk.Label(self.entry_url, text=' Loading... ', width=12, relief=tk.FLAT, height=1, fg='#FFFFFF', bg=self.TYPES)
@ -206,27 +232,29 @@ class GUI:
return self.load_home_screen(history)
else:
data = {'type': '3', 'body': '3ERROR: Improperly formatted URL\tfalse\tnull.host\t1\n'}
return False #error handling goes here
# return False
elif parsed_url['protocol'] == 'http://':
wb.open(url,2,True)
self.populate_url_bar(self.history[-1])
self.loading_bar.destroy()
return False
self.populate_url_bar(url)
if history:
self.add_to_history(url)
if parsed_url['type'] == '7':
if parsed_url and parsed_url['type'] == '7':
self.show_search()
return False # display search
elif not parsed_url:
pass
data = {'type': '3', 'body': '3ERROR: Improperly formatted URL\tfalse\tnull.host\t1\n'}
else:
data = self.execute_address(parsed_url)
if not data:
return False #error handling goes here
self.send_to_screen(data['body'],data['type'])
def parse_url(self, url=False):
parsed_url = self.parser.parse_url(url)
@ -295,14 +323,11 @@ class GUI:
def go_forward(self, event):
if len(self.history) <= 1 or self.history_location >= len(self.history) - 1:
return False
self.history_location += 1
href = self.history[self.history_location]
self.handle_request(False, href, False)
#-------------Start view methods----------------
@ -392,7 +417,8 @@ class GUI:
tag_name = 'link{}'.format(self.link_count)
callback = (lambda event, href=link, tag_name=tag_name: self.gotolink(event, href, tag_name))
favorite = [x for x in self.config['favorites'] if x['url'] == link]
# favorite = [x for x in self.config['favorites'] if x['url'] == link]
favorite = self.is_favorite(link)
self.site_display.tag_bind(tag_name, "<Button-1>", callback)
self.site_display.insert(tk.END, types[x['type']], ('type_tag',))
self.site_display.insert(tk.END,'\t\t')
@ -403,6 +429,7 @@ class GUI:
styletag = 'favoritecolor'
else:
styletag = 'linkcolor'
hover = (lambda event, href=link, tag_name=tag_name: self.hoverlink(event, href, tag_name))
clear = (lambda event, tag_name=tag_name: self.clear_status(event, tag_name))
self.site_display.tag_bind(tag_name, "<Enter>", hover)
@ -420,18 +447,47 @@ class GUI:
data = data[:-2]
self.site_display.config(state=tk.NORMAL)
self.site_display.delete(1.0, tk.END)
self.site_display.insert(tk.END, data)
self.site_display.insert(tk.END, data, 'generic_r_click')
self.site_display.config(state=tk.DISABLED)
def show_image(self, data):
self.current_image = self.build_image(data)
callback = (lambda event, image=data, write='wb': self.write_to_file(contents=image, event=event, write=write))
hover = (lambda event, href='Download this image...', tag_name='image_download': self.hoverlink(event, href, tag_name))
clear = (lambda event, tag_name='image_download': self.clear_status(event, tag_name))
self.site_display.tag_bind('image_download', "<Button-1>", callback)
self.site_display.tag_bind('image_download', "<Enter>", hover)
self.site_display.tag_bind('image_download', '<Leave>', clear)
self.site_display.config(state=tk.NORMAL)
self.site_display.delete(1.0, tk.END)
self.site_display.insert(tk.END,'Download this image',('linkcolor','image_download'))
self.site_display.insert(tk.END, '\n\n')
self.site_display.image_create(tk.END, image = self.current_image)
self.site_display.config(state=tk.DISABLED)
def show_bin_download(self, data):
url = self.entry_url.get()
filename = url.rpartition('/')
if len(filename) > 1:
filename = filename[-1]
else:
filename = ''
callback = (lambda event, bindata=data, write='wb': self.write_to_file(contents=bindata, event=event, write=write))
hover = (lambda event, href='Download {}'.format(filename), tag_name='bin_download': self.hoverlink(event, href, tag_name))
clear = (lambda event, tag_name='bin_download': self.clear_status(event, tag_name))
self.site_display.tag_bind('bin_download', "<Button-1>", callback)
self.site_display.tag_bind('bin_download', "<Enter>", hover)
self.site_display.tag_bind('bin_download', '<Leave>', clear)
self.site_display.config(state=tk.NORMAL)
self.site_display.delete(1.0, tk.END)
self.site_display.insert(tk.END,'Download ')
self.site_display.insert(tk.END,filename,('linkcolor','bin_download'))
self.site_display.config(state=tk.DISABLED)
def send_to_screen(self, data, itemtype='1', clear=True):
if itemtype == '0':
self.show_text(data)
@ -440,6 +496,8 @@ class GUI:
self.show_menu(data, clear)
elif itemtype in ['p','I','g']:
self.show_image(data)
elif itemtype in ['s','9','M','c',';','d','5']:
self.show_bin_download(data)
try:
self.loading_bar.destroy()
@ -562,6 +620,23 @@ class GUI:
return True
def write_to_file(self, contents=None, page_url=None, event=None, write='w'):
url = self.entry_url.get()
filetype = url.rpartition('.')
if len(filetype) > 1:
filetype = filetype[-1]
else:
filetype = 'txt'
filename = savedialog(initialdir="~/Desktop/", defaultextension='.{}'.format(filetype), title="Save As File", filetypes=((filetype,'*.{}'.format(filetype)),('all files','*.*')))
if not filename or filename is None or contents is None:
return False
with open(filename, write) as f:
f.write(contents)
return True
if __name__ == '__main__':
app = GUI()
app.root.mainloop()

View File

@ -10,7 +10,11 @@ i##########CONTENT PORTALS########## false null.host 1
i false null.host 1
1Floodgap / gopher.floodgap.com 70
1Super Dimensional Fortress / sdf.org 70
<<<<<<< HEAD
1Circumlunar Space / circumlunar.space 70
=======
7Veronica-2: Search Engine /v2/vs gopher.floodgap.com 70
>>>>>>> upstream/develop
i false null.host 1
i false null.host 1
i#############FAVORITES############# false null.host 1

View File

@ -1,7 +1,7 @@
import re
# Handles parsing gopher data:
# URLs, Menus
# URLs, Menus
class parser:
@ -18,7 +18,7 @@ class parser:
if url == 'home':
return False
regex = r'^(?P<protocol>(?:(gopher|http):\/\/)?)?(?P<host>[\w\-\.\d]+)(?P<port>(?::\d+)?)?(?P<type>(?:\/[\dgIp])?)?(?P<resource>(?:\/.*)?)?$'
regex = r'^(?P<protocol>(?:(gopher|http):\/\/)?)?(?P<host>[\w\-\.\d]+)(?P<port>(?::\d+)?)?(?P<type>(?:\/[01345679gIhisp])?)?(?P<resource>(?:\/.*)?)?$'
match = re.match(regex, url)
@ -37,6 +37,9 @@ class parser:
if not resource:
resource = '/'
if not itemtype:
itemtype = '1'
self.filetype = itemtype[len(itemtype) - 1] if itemtype else '1'
self.protocol = protocol if protocol else 'gopher://'