#!/usr/bin/env python

"""
Copyright (c) 2006-2024 sqlmap developers (https://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""

import sys  # 导入sys模块，用于处理与Python解释器相关的操作

sys.dont_write_bytecode = True  # 设置不生成.pyc字节码文件，以减少磁盘空间占用和加载时间

__import__("lib.utils.versioncheck")  # 动态导入lib.utils.versioncheck模块，通常用于检查版本兼容性

import logging  # 导入logging模块，用于记录日志信息
import os  # 导入os模块，用于与操作系统进行交互
import warnings  # 导入warnings模块，用于处理警告信息

warnings.filterwarnings(action="ignore", category=UserWarning)  # 忽略所有UserWarning类别的警告
warnings.filterwarnings(action="ignore", category=DeprecationWarning)  # 忽略所有DeprecationWarning类别的警告

try:
    from optparse import OptionGroup  # 从optparse模块导入OptionGroup类，用于处理命令行选项组
    from optparse import OptionParser as ArgumentParser  # 从optparse模块导入OptionParser类，并将其重命名为ArgumentParser

    ArgumentParser.add_argument = ArgumentParser.add_option  # 将ArgumentParser的add_option方法重命名为add_argument，以兼容argparse的API

    def _add_argument(self, *args, **kwargs):  # 定义一个辅助函数_add_argument，用于将add_argument方法映射到add_option方法
        return self.add_option(*args, **kwargs)

    OptionGroup.add_argument = _add_argument  # 将OptionGroup的add_argument方法映射到_add_argument函数

except ImportError:  # 如果导入optparse模块失败（例如在Python 3中），则执行以下代码
    from argparse import ArgumentParser  # 从argparse模块导入ArgumentParser类，用于处理命令行参数

finally:  # 无论try块中的代码是否成功执行，finally块中的代码都会执行
    def get_actions(instance):  # 定义一个函数get_actions，用于获取命令行解析器实例中的选项列表
        for attr in ("option_list", "_group_actions", "_actions"):  # 遍历可能的属性名称
            if hasattr(instance, attr):  # 如果实例具有该属性
                return getattr(instance, attr)  # 返回该属性的值

    def get_groups(parser):  # 定义一个函数get_groups，用于获取命令行解析器中的选项组
        return getattr(parser, "option_groups", None) or getattr(parser, "_action_groups")  # 返回解析器中的选项组，如果不存在则返回None

    def get_all_options(parser):  # 定义一个函数get_all_options，用于获取命令行解析器中的所有选项
        retVal = set()  # 创建一个空集合，用于存储所有选项

        for option in get_actions(parser):  # 遍历解析器中的选项
            if hasattr(option, "option_strings"):  # 如果选项具有option_strings属性
                retVal.update(option.option_strings)  # 将选项字符串添加到集合中
            else:  # 否则
                retVal.update(option._long_opts)  # 将长选项添加到集合中
                retVal.update(option._short_opts)  # 将短选项添加到集合中

        for group in get_groups(parser):  # 遍历解析器中的选项组
            for option in get_actions(group):  # 遍历选项组中的选项
                if hasattr(option, "option_strings"):  # 如果选项具有option_strings属性
                    retVal.update(option.option_strings)  # 将选项字符串添加到集合中
                else:  # 否则
                    retVal.update(option._long_opts)  # 将长选项添加到集合中
                    retVal.update(option._short_opts)  # 将短选项添加到集合中

        return retVal  # 返回包含所有选项的集合


from lib.core.common import getUnicode  # 从lib.core.common模块导入getUnicode函数，用于将字符串转换为Unicode格式
from lib.core.common import setPaths  # 从lib.core.common模块导入setPaths函数，用于设置文件路径
from lib.core.data import logger  # 从lib.core.data模块导入logger对象，用于记录日志信息
from lib.core.patch import dirtyPatches  # 从lib.core.patch模块导入dirtyPatches函数，用于应用临时补丁
from lib.core.patch import resolveCrossReferences  # 从lib.core.patch模块导入resolveCrossReferences函数，用于解决交叉引用问题
from lib.core.settings import RESTAPI_DEFAULT_ADAPTER  # 从lib.core.settings模块导入RESTAPI_DEFAULT_ADAPTER常量，表示默认的服务器适配器
from lib.core.settings import RESTAPI_DEFAULT_ADDRESS  # 从lib.core.settings模块导入RESTAPI_DEFAULT_ADDRESS常量，表示默认的服务器地址
from lib.core.settings import RESTAPI_DEFAULT_PORT  # 从lib.core.settings模块导入RESTAPI_DEFAULT_PORT常量，表示默认的服务器端口
from lib.core.settings import UNICODE_ENCODING  # 从lib.core.settings模块导入UNICODE_ENCODING常量，表示默认的Unicode编码
from lib.utils.api import client  # 从lib.utils.api模块导入client函数，用于启动REST-JSON API客户端
from lib.utils.api import server  # 从lib.utils.api模块导入server函数，用于启动REST-JSON API服务器

try:
    from sqlmap import modulePath  # 从sqlmap模块导入modulePath函数，用于获取模块路径
except ImportError:  # 如果导入失败（例如sqlmap模块不存在），则执行以下代码
    def modulePath():  # 定义一个函数modulePath，用于获取当前模块的路径
        return getUnicode(os.path.dirname(os.path.realpath(__file__)), encoding=sys.getfilesystemencoding() or UNICODE_ENCODING)  # 返回当前文件的目录路径，并将其转换为Unicode格式

def main():  # 定义main函数，作为REST-JSON API的入口函数
    """
    REST-JSON API main function
    """

    dirtyPatches()  # 应用临时补丁
    resolveCrossReferences()  # 解决交叉引用问题

    # Set default logging level to debug
    logger.setLevel(logging.DEBUG)  # 设置日志记录级别为DEBUG，以便记录详细信息

    # Initialize paths
    setPaths(modulePath())  # 初始化文件路径，使用modulePath函数获取当前模块路径

    # Parse command line options
    apiparser = ArgumentParser()  # 创建一个ArgumentParser对象，用于解析命令行参数
    apiparser.add_argument("-s", "--server", help="Run as a REST-JSON API server", action="store_true")  # 添加一个命令行选项，用于启动服务器
    apiparser.add_argument("-c", "--client", help="Run as a REST-JSON API client", action="store_true")  # 添加一个命令行选项，用于启动客户端
    apiparser.add_argument("-H", "--host", help="Host of the REST-JSON API server (default \"%s\")" % RESTAPI_DEFAULT_ADDRESS, default=RESTAPI_DEFAULT_ADDRESS)  # 添加一个命令行选项，用于指定服务器主机地址，默认值为RESTAPI_DEFAULT_ADDRESS
    apiparser.add_argument("-p", "--port", help="Port of the REST-JSON API server (default %d)" % RESTAPI_DEFAULT_PORT, default=RESTAPI_DEFAULT_PORT, type=int)  # 添加一个命令行选项，用于指定服务器端口，默认值为RESTAPI_DEFAULT_PORT
    apiparser.add_argument("--adapter", help="Server (bottle) adapter to use (default \"%s\")" % RESTAPI_DEFAULT_ADAPTER, default=RESTAPI_DEFAULT_ADAPTER)  # 添加一个命令行选项，用于指定服务器适配器，默认值为RESTAPI_DEFAULT_ADAPTER
    apiparser.add_argument("--database", help="Set IPC database filepath (optional)")  # 添加一个命令行选项，用于指定IPC数据库文件路径（可选）
    apiparser.add_argument("--username", help="Basic authentication username (optional)")  # 添加一个命令行选项，用于指定基本认证的用户名（可选）
    apiparser.add_argument("--password", help="Basic authentication password (optional)")  # 添加一个命令行选项，用于指定基本认证的密码（可选）
    (args, _) = apiparser.parse_known_args() if hasattr(apiparser, "parse_known_args") else apiparser.parse_args()  # 解析命令行参数，如果支持parse_known_args方法则使用它，否则使用parse_args方法

    # Start the client or the server
    if args.server:  # 如果命令行参数中指定了启动服务器
        server(args.host, args.port, adapter=args.adapter, username=args.username, password=args.password, database=args.database)  # 调用server函数启动服务器
    elif args.client:  # 如果命令行参数中指定了启动客户端
        client(args.host, args.port, username=args.username, password=args.password)  # 调用client函数启动客户端
    else:  # 如果未指定启动服务器或客户端
        apiparser.print_help()  # 打印命令行帮助信息

if __name__ == "__main__":  # 如果当前脚本作为主程序运行
    main()  # 调用main函数
