diff --git a/auth-sample b/auth-sample
index 737f0b3..92aaec9 100644
--- a/auth-sample
+++ b/auth-sample
@@ -1,3 +1,4 @@
-2020111222
-Bistu111222
-192.168.211.3
+[DEFAULT]
+username = 2020000000
+password = Bistu000000
+host = 192.168.211.3
diff --git a/bistu_wifi/__init__.py b/bistu_wifi/__init__.py
new file mode 100644
index 0000000..79382cc
--- /dev/null
+++ b/bistu_wifi/__init__.py
@@ -0,0 +1,2 @@
+from .bistu_wifi import login
+from .bistu_wifi import logout
diff --git a/bistu_wifi/__main__.py b/bistu_wifi/__main__.py
new file mode 100644
index 0000000..898a053
--- /dev/null
+++ b/bistu_wifi/__main__.py
@@ -0,0 +1,86 @@
+#!/usr/bin/python3
+
+import os
+import logging
+import configparser
+import argparse
+from bistu_wifi.bistu_wifi import logger
+from bistu_wifi.bistu_wifi import login
+from bistu_wifi.bistu_wifi import logout
+
+
+if 'XDG_CONFIG_HOME' in os.environ:
+ XDG_CONFIG_HOME = os.environ['XDG_CONFIG_HOME']
+else:
+ XDG_CONFIG_HOME = os.path.join(os.environ['HOME'], '.config')
+
+DEFAULT_HOST = '10.1.206.13'
+DEFAULT_CONFIG_LOCATION = os.path.join(XDG_CONFIG_HOME, 'bistu-wifi/auth.ini')
+
+
+def main():
+
+ parser = argparse.ArgumentParser()
+ parser.description = 'login or logout bistu wifi'
+
+ parser.add_argument('-u', '--username', nargs='?',
+ type=str, help='username you use to login bistu wifi')
+ parser.add_argument('-p', '--password', nargs='?',
+ type=str, help='password you use to login bistu wifi')
+ parser.add_argument('--host', nargs='?', default=None,
+ type=str, help='host to send login/logout request to, default use 10.1.206.13')
+ parser.add_argument('-o', '--logout', action='store_true',
+ help='logout bistu wifi. try to login if not privided')
+ parser.add_argument('-c', '--config', nargs='?', default=DEFAULT_CONFIG_LOCATION,
+ type=str, help='load info(username, password, host) from config file')
+ parser.add_argument('--notime', action='store_true',
+ help='don\'t output time field in log')
+
+ args = parser.parse_args()
+
+ log_level = logging.DEBUG if 'BISTU_WIFI_DEBUG' in os.environ else logging.INFO
+ log_fmt = '%(levelname)s : %(funcName)s : %(message)s'
+ if not args.notime:
+ log_fmt = '%(asctime)s : ' + log_fmt
+
+ logging.basicConfig(level=log_level, format=log_fmt)
+
+ username = None
+ password = None
+ host = DEFAULT_HOST
+ is_logout = False
+
+ if args.config is not None:
+ logger.info('loading info from config file %s ...', args.config)
+
+ config = configparser.ConfigParser()
+ config.read(args.config)
+
+ d_section = config['DEFAULT']
+
+ username = str(d_section['username']) if 'username' in d_section else username
+ password = str(d_section['password']) if 'password' in d_section else password
+ host = str(d_section['host']) if 'host' in d_section else host
+
+ username = args.username if args.username is not None else username
+ password = args.password if args.password is not None else password
+ host = args.host if args.host is not None else host
+
+ is_logout = args.logout
+
+ logger.info('parameter status: username = %s', username)
+ logger.info('parameter status: password = %s', None if password is None else '*' * len(password))
+ logger.info('parameter status: host = %s', host)
+ logger.info('parameter status: logout = %s', is_logout)
+
+ if is_logout:
+ logout(host)
+ else:
+ if username is None or password is None:
+ logger.error('cannot login wifi without username or password')
+ else:
+ login(username, password, host)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/bistu_wifi/bistu_wifi.py b/bistu_wifi/bistu_wifi.py
new file mode 100644
index 0000000..7879c18
--- /dev/null
+++ b/bistu_wifi/bistu_wifi.py
@@ -0,0 +1,112 @@
+#!/usr/bin/python3
+
+import urllib.parse
+import urllib.request
+import urllib.response
+import logging
+import re
+
+
+logger = logging.getLogger('bistu-wifi')
+
+
+def generate_post_data(username: str, password: str):
+ '''
+ Generate bytes to send to through HTTP POST, an example from browser:
+
+ DDDDD=2021020000&upass=Bistu000000&R1=0&R2=&R3=0&R6=0¶=00&0MKKey=123456&buttonClicked=&redirect_url=&err_flag=&username=&password=&user=&cmd=&Login=
+ '''
+
+ data_template = {
+ 'DDDDD': None,
+ 'upass': None,
+ 'R1': 0,
+ 'R2': '',
+ 'R3': 0,
+ 'R6': 0,
+ 'para': 00,
+ '0MKKey': 123456,
+ 'buttonClicked': '',
+ 'redirect_url': '',
+ 'err_flag': '',
+ 'username': '',
+ 'password': '',
+ 'user': '',
+ 'cmd': '',
+ 'Login': ''
+ }
+
+ data_template['DDDDD'] = username
+ data_template['upass'] = password
+
+ # login_manager.generate_post_data_hook(data_template)
+
+ for k, v in data_template.items():
+ logger.debug('the generated post data: %s: %s', k, v)
+
+ return bytes(urllib.parse.urlencode(data_template), 'utf-8')
+
+
+def login(username: str, password: str, host: str):
+ '''
+ There are some other host, the known are:
+
+ - 10.1.206.3 (default)
+ - 192.168.211.3
+ '''
+
+ login_url = f'http://{host}/a70.htm'
+
+ headers = {
+ 'Content-Type': 'application/x-www-form-urlencoded',
+ 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
+ 'Accept-Language': 'en-US,zh-CN;q=0.5',
+ 'Accept-Encoding': 'gzip, deflate'
+ }
+
+ post_data = generate_post_data(username, password)
+
+ logger.debug('the dest url is: %s', login_url)
+ for k, v in headers.items():
+ logger.debug('the headers: %s: %s', k, v)
+ logger.debug('the encoded post data: %s', str(post_data))
+
+ req = urllib.request.Request(url=login_url, data=post_data, headers=headers, method='POST')
+
+ logger.info('sending the login request...')
+
+ with urllib.request.urlopen(req) as response:
+ response_body = response.read().decode('gbk')
+
+ html_title = re.search('
(.*)', response_body)[1]
+
+ logger.info('http_status: %d', response.status)
+ logger.info('title_of_response_html: %s', html_title)
+ logger.info('login_state: %s', 'success' if html_title == '认证成功页' else 'fail')
+
+
+def logout(host: str):
+ '''
+ param host: see login host
+ '''
+
+ logout_url = f'http://{host}/F.htm'
+ req = urllib.request.Request(url=logout_url)
+
+ logger.info('sending the logout request...')
+
+ with urllib.request.urlopen(req) as response:
+ response_body = response.read().decode('gbk')
+
+ html_title = re.search('(.*)', response_body)[1]
+
+ logger.info('http_status: %d', response.status)
+ logger.info('title_of_response_html: %s', html_title)
+ logger.info('logout_state: %s', 'success' if html_title == '信息页' else 'fail')
+
+#@staticmethod
+#def generate_post_data_hook(post_data: dict) -> None:
+# username = post_data['DDDDD']
+# username += '@bistu'
+# post_data['DDDDD'] = username
+
diff --git a/main.py b/main.py
deleted file mode 100644
index e9b8c45..0000000
--- a/main.py
+++ /dev/null
@@ -1,167 +0,0 @@
-#!/usr/bin/python3
-
-import urllib.parse
-import urllib.request
-import urllib.response
-import logging
-import re
-import argparse
-
-logger = logging.getLogger('login_manager')
-
-def generate_post_data(username: str, password: str):
- '''
- Generate bytes to send to through HTTP POST, an example from browser:
-
- DDDDD=2021020000&upass=Bistu000000&R1=0&R2=&R3=0&R6=0¶=00&0MKKey=123456&buttonClicked=&redirect_url=&err_flag=&username=&password=&user=&cmd=&Login=
- '''
-
- data_template = {
- 'DDDDD': None,
- 'upass': None,
- 'R1': 0,
- 'R2': '',
- 'R3': 0,
- 'R6': 0,
- 'para': 00,
- '0MKKey': 123456,
- 'buttonClicked': '',
- 'redirect_url': '',
- 'err_flag': '',
- 'username': '',
- 'password': '',
- 'user': '',
- 'cmd': '',
- 'Login': ''
- }
-
- data_template['DDDDD'] = username
- data_template['upass'] = password
-
- # login_manager.generate_post_data_hook(data_template)
-
- logger.debug('the generated post data is %s', str(data_template))
-
- return bytes(urllib.parse.urlencode(data_template), 'utf-8')
-
-def login(username: str, password: str, host: str = '10.1.206.13'):
- '''
- There are some other host, the known are:
-
- - 10.1.206.3 (default)
- - 192.168.211.3
- '''
- headers = {
- 'Content-Type': 'application/x-www-form-urlencoded',
- 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
- 'Accept-Language': 'en-US,zh-CN;q=0.5',
- 'Accept-Encoding': 'gzip, deflate'
- }
- post_data = generate_post_data(username, password)
-
- login_url = f'http://{host}/a70.htm'
- logger.debug('the dest url is: %s', login_url)
- logger.debug('the headers is: %s', str(headers))
- logger.debug('the encoded post data is %s', str(post_data))
-
- req = urllib.request.Request(url=login_url, data=post_data, headers=headers, method='POST')
-
- logger.info('sending the login request...')
-
- with urllib.request.urlopen(req) as response:
- response_body = response.read().decode('gbk')
-
- html_title = re.search('(.*)', response_body)[1]
-
- logger.info('http_status: %d', response.status)
- logger.info('title_of_response_html: %s', html_title)
- logger.info('login_state: %s', 'success' if html_title == '认证成功页' else 'fail')
-
-def logout(host: str = '10.1.206.13'):
- '''
- param host: see login host
- '''
-
- logout_url = f'http://{host}/F.htm'
- req = urllib.request.Request(url=logout_url)
-
- logger.info('sending the logout request...')
-
- with urllib.request.urlopen(req) as response:
- response_body = response.read().decode('gbk')
-
- html_title = re.search('(.*)', response_body)[1]
-
- logger.info('http_status: %d', response.status)
- logger.info('title_of_response_html: %s', html_title)
- logger.info('logout_state: %s', 'success' if html_title == '信息页' else 'fail')
-
- #@staticmethod
- #def generate_post_data_hook(post_data: dict) -> None:
- # username = post_data['DDDDD']
- # username += '@bistu'
- # post_data['DDDDD'] = username
-
-
-def load_auth_info(path: str):
- with open(path, 'r', encoding='utf-8') as file:
- username = file.readline().strip()
- password = file.readline().strip()
-
- host = file.readline().strip()
- if host == '':
- host = None
-
- return username, password, host
-
-def main():
- logging.basicConfig(level=logging.DEBUG)
- logger = logging.getLogger('main')
-
- parser = argparse.ArgumentParser()
- parser.description = 'login or logout bistu wifi'
- parser.epilog = 'the config file format(without quote): "{username}\\n{password}". The "\\n" is a newline charactor'
-
- parser.add_argument('-u', '--username', nargs='?',
- type=str, help='username you use to login bistu wifi, logout if not provided')
- parser.add_argument('-p', '--password', nargs='?',
- type=str, help='password you use to login bistu wifi, logout if not provided')
- parser.add_argument('--host', nargs='?', default=None,
- type=str, help='host to send login/logout request to, default use 10.1.206.13')
- parser.add_argument('-o', '--logout', nargs='?', type=bool, default=False,
- help='logout bistu wifi')
- parser.add_argument('-c', '--config', nargs='?', type=str,
- help='load info(username, password, host) from config file')
-
- args = parser.parse_args()
-
- logger.debug('parse argument: username= %s', args.username)
- logger.debug('parse argument: password= %s', args.password)
- logger.debug('parse argument: host= %s', args.host)
- logger.debug('parse argument: logout= %s', args.logout)
-
- if args.config is not None:
- username, password, host = load_auth_info(args.config)
-
- if host is None:
- login(username, password)
- else:
- login(username, password, host)
-
- elif args.username is not None and args.password is not None:
- if args.host is None:
- login(args.username, args.password)
- else:
- login(args.username, args.password, args.host)
-
- elif args.logout:
- if args.host is None:
- logout()
- else:
- logout(args.host)
- else:
- parser.print_help()
-
-
-if __name__ == '__main__':
- main()
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 0000000..d2aa7f5
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,6 @@
+[project]
+name = "bistu_wifi"
+version = "0.0.1"
+dependencies = []
+[project.scripts]
+bistu-wifi = "bistu_wifi.__main__:main"