#include "bsphp_client.h"
#include "bsphp_config.h"
#include "bsphp_crypto.h"

#include <windows.h>
#include <winhttp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <stdarg.h>

/*
 * BSPHP LOGIN 客户端（C 版）
 * ----------------------------------------
 * 1) bsphp_send_raw():
 *    组包(含 appsafecode/md5/mutualkey) -> AES 加密 -> RSA 签名加密 -> WinHTTP POST
 * 2) decrypt_server_response():
 *    拆分 OK|aes|rsa -> RSA 解签名得到响应 AES key -> AES 解密得到 JSON
 * 3) 业务接口:
 *    通过 bsphp_send_raw() 封装成 int bsphp_xxx(...)，返回 1/0。
 *
 * 返回约定：
 * - 成功返回 1，失败返回 0
 * - out_resp 为 malloc 的解密后 JSON 文本，调用方负责 free()
 */

typedef struct {
    char *data;
    size_t len;
} mem_buf_t;

static void bsphp_trace(int v, const char *fmt, ...) {
    va_list ap;
    if (!v) return;
    va_start(ap, fmt);
    vprintf(fmt, ap);
    va_end(ap);
    fflush(stdout);
}

static void bsphp_trace_str(int v, const char *label, const char *s) {
    enum { kMax = 4096 };
    size_t n;
    if (!v) return;
    if (!s) {
        printf("%s(null)\n", label);
        fflush(stdout);
        return;
    }
    n = strlen(s);
    if (n <= (size_t)kMax) {
        printf("%s%s\n", label, s);
    } else {
        printf("%s%.*s ...[truncated total=%zu bytes]\n", label, kMax, s, n);
    }
    fflush(stdout);
}

static wchar_t *utf8_to_wide(const char *s) {
    int n = MultiByteToWideChar(CP_UTF8, 0, s, -1, NULL, 0);
    wchar_t *out = (wchar_t *)malloc((size_t)n * sizeof(wchar_t));
    if (!out) return NULL;
    MultiByteToWideChar(CP_UTF8, 0, s, -1, out, n);
    return out;
}

static void now_formats(char out_normal[20], char out_hash[20]) {
    time_t t = time(NULL);
    struct tm tmv;
#ifdef _WIN32
    localtime_s(&tmv, &t);
#else
    localtime_r(&t, &tmv);
#endif
    strftime(out_normal, 20, "%Y-%m-%d %H:%M:%S", &tmv);
    strftime(out_hash, 20, "%Y-%m-%d#%H:%M:%S", &tmv);
}

/* 发送 application/x-www-form-urlencoded 到 BSPHP API。 */
static int http_post_form(const char *url, const char *form_body, char **out_text) {
    int ok = 0;
    wchar_t *wurl = NULL;
    URL_COMPONENTS uc;
    wchar_t host[256];
    wchar_t path[2048];
    INTERNET_PORT port;
    HINTERNET hSession = NULL, hConnect = NULL, hRequest = NULL;
    DWORD flags = 0, sent = 0, avail = 0, readn = 0;
    mem_buf_t chunk = {0};

    memset(&uc, 0, sizeof(uc));
    uc.dwStructSize = sizeof(uc);
    uc.lpszHostName = host;
    uc.dwHostNameLength = (DWORD)(sizeof(host) / sizeof(host[0]));
    uc.lpszUrlPath = path;
    uc.dwUrlPathLength = (DWORD)(sizeof(path) / sizeof(path[0]));

    wurl = utf8_to_wide(url);
    if (!wurl) goto done;
    if (!WinHttpCrackUrl(wurl, 0, 0, &uc)) goto done;
    port = uc.nPort;
    if (uc.nScheme == INTERNET_SCHEME_HTTPS) flags |= WINHTTP_FLAG_SECURE;

    hSession = WinHttpOpen(L"BSPHP-C-DEMO/1.0", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
                           WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
    if (!hSession) goto done;
    hConnect = WinHttpConnect(hSession, host, port, 0);
    if (!hConnect) goto done;
    hRequest = WinHttpOpenRequest(hConnect, L"POST", path, NULL,
                                  WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, flags);
    if (!hRequest) goto done;

    if (!WinHttpAddRequestHeaders(hRequest,
                                  L"Content-Type: application/x-www-form-urlencoded\r\n",
                                  (DWORD)-1, WINHTTP_ADDREQ_FLAG_ADD)) goto done;

    if (!WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0,
                            (LPVOID)form_body, (DWORD)strlen(form_body),
                            (DWORD)strlen(form_body), 0)) goto done;
    if (!WinHttpReceiveResponse(hRequest, NULL)) goto done;

    do {
        if (!WinHttpQueryDataAvailable(hRequest, &avail)) goto done;
        if (avail == 0) break;
        {
            char *buf = (char *)malloc(avail + 1);
            char *newp;
            if (!buf) goto done;
            if (!WinHttpReadData(hRequest, buf, avail, &readn)) {
                free(buf);
                goto done;
            }
            buf[readn] = '\0';
            newp = (char *)realloc(chunk.data, chunk.len + readn + 1);
            if (!newp) {
                free(buf);
                goto done;
            }
            chunk.data = newp;
            memcpy(chunk.data + chunk.len, buf, readn);
            chunk.len += readn;
            chunk.data[chunk.len] = '\0';
            free(buf);
        }
    } while (avail > 0);

    *out_text = chunk.data;
    chunk.data = NULL;
    ok = 1;

done:
    if (!ok && chunk.data) free(chunk.data);
    if (hRequest) WinHttpCloseHandle(hRequest);
    if (hConnect) WinHttpCloseHandle(hConnect);
    if (hSession) WinHttpCloseHandle(hSession);
    if (wurl) free(wurl);
    (void)sent;
    return ok;
}

static int parse_json_value(const char *json, const char *key, char *out, size_t out_size) {
    /* Lightweight parser for "key":"value"; for demo only. */
    char pattern[128];
    char *p, *q;
    snprintf(pattern, sizeof(pattern), "\"%s\":\"", key);
    p = strstr((char *)json, pattern);
    if (!p) return 0;
    p += strlen(pattern);
    q = strchr(p, '"');
    if (!q) return 0;
    if ((size_t)(q - p) >= out_size) return 0;
    memcpy(out, p, (size_t)(q - p));
    out[q - p] = '\0';
    return 1;
}

/* 解密服务端返回：OK|aes_b64|rsa_b64 -> JSON 文本。 */
static int decrypt_server_response(bsphp_client_t *c, const char *api, const char *raw_text,
                                   char **out_plain_json) {
    char *work = _strdup(raw_text);
    char *p1, *p2;
    char *enc_b64;
    char *rsa_b64;
    char *sig_plain = NULL;
    char *json_plain = NULL;
    char *k1, *k2, *k3;
    char aes_key[17];
    int ok = 0;
    if (!work) return 0;

    bsphp_trace(c->verbose, "[BSPHP][%s] --- HTTP raw body ---\n", api);
    bsphp_trace_str(c->verbose, "", raw_text);

    p1 = strchr(work, '|');
    if (!p1) {
        bsphp_trace(c->verbose, "[BSPHP][%s] error: no '|'\n", api);
        goto done;
    }
    p2 = strchr(p1 + 1, '|');
    if (!p2) {
        bsphp_trace(c->verbose, "[BSPHP][%s] error: need 2 '|'\n", api);
        goto done;
    }
    *p1 = '\0';
    *p2 = '\0';
    enc_b64 = p1 + 1;
    rsa_b64 = p2 + 1;

    bsphp_trace(c->verbose, "[BSPHP][%s] decrypt-before: first=%s\n", api, work);
    bsphp_trace(c->verbose, "[BSPHP][%s] decrypt-before: AES b64\n", api);
    bsphp_trace_str(c->verbose, "", enc_b64);
    bsphp_trace(c->verbose, "[BSPHP][%s] decrypt-before: RSA b64\n", api);
    bsphp_trace_str(c->verbose, "", rsa_b64);

    if (!bsphp_rsa_decrypt_pkcs1_base64(rsa_b64, c->server_private_key, &sig_plain)) {
        bsphp_trace(c->verbose, "[BSPHP][%s] error: RSA decrypt\n", api);
        goto done;
    }
    bsphp_trace(c->verbose, "[BSPHP][%s] RSA-decrypt signature\n", api);
    bsphp_trace_str(c->verbose, "", sig_plain);

    k1 = strchr(sig_plain, '|');
    if (!k1) goto done;
    k2 = strchr(k1 + 1, '|');
    if (!k2) goto done;
    k3 = strchr(k2 + 1, '|');
    if (!k3) goto done;
    if ((k3 - (k2 + 1)) < 16) goto done;
    memcpy(aes_key, k2 + 1, 16);
    aes_key[16] = '\0';
    bsphp_trace(c->verbose, "[BSPHP][%s] response AES key=%s\n", api, aes_key);

    if (!bsphp_aes128_cbc_decrypt_base64(enc_b64, aes_key, &json_plain)) {
        bsphp_trace(c->verbose, "[BSPHP][%s] error: AES decrypt\n", api);
        goto done;
    }
    bsphp_trace(c->verbose, "[BSPHP][%s] decrypt-after JSON\n", api);
    bsphp_trace_str(c->verbose, "", json_plain);
    *out_plain_json = json_plain;
    json_plain = NULL;
    ok = 1;

done:
    if (work) free(work);
    if (sig_plain) free(sig_plain);
    if (json_plain) free(json_plain);
    return ok;
}

/* 加载配置到客户端上下文。 */
void bsphp_client_init(bsphp_client_t *c) {
    memset(c, 0, sizeof(*c));
    c->url = BSPHP_API_URL;
    c->mutual_key = BSPHP_MUTUAL_KEY;
    c->server_private_key = BSPHP_SERVER_PRIVATE_KEY_B64;
    c->client_public_key = BSPHP_CLIENT_PUBLIC_KEY_B64;
    c->code_url_prefix = BSPHP_CODE_URL_PREFIX;
    c->signature_tail = BSPHP_SIGNATURE_TAIL;
    c->verbose = 0;
}

/* 开关详细日志输出。 */
void bsphp_client_set_verbose(bsphp_client_t *c, int on) {
    if (!c) return;
    c->verbose = on ? 1 : 0;
}

/* 修改签名尾（json/XML）。 */
void bsphp_client_set_signature_tail(bsphp_client_t *c, const char *tail) {
    if (!c || !tail || !tail[0]) return;
    c->signature_tail = tail;
}

/* 手动覆盖会话 SeSsL（用于复用会话）。 */
void bsphp_client_set_sessl(bsphp_client_t *c, const char *sessl) {
    strncpy(c->bsphp_sessl, sessl, sizeof(c->bsphp_sessl) - 1);
}

/* 核心发送函数：负责请求加密、签名、POST、响应解密。 */
int bsphp_send_raw(bsphp_client_t *c, const char *api, const char *extra_query, char **out_resp) {
    char t1[20], t2[20], appsafecode[33], key_md5[33], md5_self[33];
    char aes_key[17], sig_md5[33];
    char req_plain[4096], md5_seed[4096];
    char signature[256];
    char *enc_b64 = NULL, *rsa_b64 = NULL, *payload = NULL, *encoded = NULL, *form = NULL;
    char *http_text = NULL, *resp_copy = NULL;
    int ok = 0;

    now_formats(t1, t2);
    bsphp_md5_hex(t1, appsafecode);
    snprintf(md5_seed, sizeof(md5_seed),
             "api=%s&BSphpSeSsL=%s&date=%s&mutualkey=%s&appsafecode=%s%s%s",
             api, c->bsphp_sessl, t2, c->mutual_key, appsafecode,
             (extra_query && *extra_query) ? "&" : "",
             (extra_query && *extra_query) ? extra_query : "");
    bsphp_md5_hex(md5_seed, md5_self);

    snprintf(req_plain, sizeof(req_plain),
             "api=%s&BSphpSeSsL=%s&date=%s&md5=%s&mutualkey=%s&appsafecode=%s%s%s",
             api, c->bsphp_sessl, t2, md5_self, c->mutual_key, appsafecode,
             (extra_query && *extra_query) ? "&" : "",
             (extra_query && *extra_query) ? extra_query : "");

    snprintf(signature, sizeof(signature), "%s%s", c->server_private_key, appsafecode);
    bsphp_md5_hex(signature, key_md5);
    memcpy(aes_key, key_md5, 16);
    aes_key[16] = '\0';

    bsphp_trace(c->verbose, "\n[BSPHP][%s] ========== request ==========\n", api);
    bsphp_trace(c->verbose, "[BSPHP][%s] URL=%s\n", api, c->url);
    bsphp_trace(c->verbose, "[BSPHP][%s] appsafecode=%s\n", api, appsafecode);
    bsphp_trace(c->verbose, "[BSPHP][%s] md5_seed=%s\n", api, md5_seed);
    bsphp_trace(c->verbose, "[BSPHP][%s] encrypt-before (plain)=\n", api);
    bsphp_trace_str(c->verbose, "", req_plain);
    bsphp_trace(c->verbose, "[BSPHP][%s] MD5(server+appsafe)=%s\n", api, key_md5);
    bsphp_trace(c->verbose, "[BSPHP][%s] AES key=%s\n", api, aes_key);

    if (!bsphp_aes128_cbc_encrypt_base64(req_plain, aes_key, &enc_b64)) {
        bsphp_trace(c->verbose, "[BSPHP][%s] error: AES encrypt\n", api);
        goto done;
    }
    bsphp_trace(c->verbose, "[BSPHP][%s] encrypt-after (AES b64)\n", api);
    bsphp_trace_str(c->verbose, "", enc_b64);

    bsphp_md5_hex(enc_b64, sig_md5);
    snprintf(signature, sizeof(signature), "0|AES-128-CBC|%s|%s|%s", aes_key, sig_md5,
             c->signature_tail ? c->signature_tail : "json");
    bsphp_trace(c->verbose, "[BSPHP][%s] sign string\n", api);
    bsphp_trace_str(c->verbose, "", signature);

    if (!bsphp_rsa_encrypt_pkcs1_base64(signature, c->client_public_key, &rsa_b64)) {
        bsphp_trace(c->verbose, "[BSPHP][%s] error: RSA encrypt\n", api);
        goto done;
    }
    bsphp_trace(c->verbose, "[BSPHP][%s] RSA-after (b64)\n", api);
    bsphp_trace_str(c->verbose, "", rsa_b64);

    payload = (char *)malloc(strlen(enc_b64) + strlen(rsa_b64) + 2);
    if (!payload) goto done;
    sprintf(payload, "%s|%s", enc_b64, rsa_b64);
    encoded = bsphp_url_encode(payload);
    if (!encoded) goto done;

    form = (char *)malloc(strlen(encoded) + 16);
    if (!form) goto done;
    sprintf(form, "parameter=%s", encoded);
    bsphp_trace(c->verbose, "[BSPHP][%s] POST parameter=\n", api);
    bsphp_trace_str(c->verbose, "", form);

    if (!http_post_form(c->url, form, &http_text)) {
        bsphp_trace(c->verbose, "[BSPHP][%s] error: HTTP\n", api);
        goto done;
    }
    {
        char *dec = bsphp_url_decode(http_text);
        if (dec) {
            free(http_text);
            http_text = dec;
        }
    }
    bsphp_trace(c->verbose, "[BSPHP][%s] ========== response ==========\n", api);
    if (!decrypt_server_response(c, api, http_text, &resp_copy)) goto done;
    if (!resp_copy) goto done;

    *out_resp = resp_copy;
    ok = 1;

done:
    if (enc_b64) bsphp_secure_free(enc_b64);
    if (rsa_b64) bsphp_secure_free(rsa_b64);
    if (payload) bsphp_secure_free(payload);
    if (encoded) bsphp_secure_free(encoded);
    if (form) bsphp_secure_free(form);
    if (http_text) free(http_text);
    return ok;
}

/* 初始化握手：internet.in -> BSphpSeSsL.in。 */
int bsphp_bootstrap(bsphp_client_t *c, char **out_resp) {
    char *r1 = NULL, *r2 = NULL;
    char sessl[256] = {0};
    if (!bsphp_send_raw(c, "internet.in", "", &r1)) return 0;
    free(r1);
    if (!bsphp_send_raw(c, "BSphpSeSsL.in", "", &r2)) return 0;
    if (parse_json_value(r2, "data", sessl, sizeof(sessl))) {
        bsphp_client_set_sessl(c, sessl);
    }
    *out_resp = r2;
    return 1;
}

/* gg.in：公告。 */
int bsphp_get_notice(bsphp_client_t *c, char **out_resp) {
    return bsphp_send_raw(c, "gg.in", "", out_resp);
}

/* login.lg：账号登录（user/pwd/coode/key/maxoror）。 */
int bsphp_login_lg(bsphp_client_t *c, const char *user, const char *pwd, const char *coode, const char *machine_code, char **out_resp) {
    char extra[1024];
    snprintf(extra, sizeof(extra), "user=%s&pwd=%s&coode=%s&key=%s&maxoror=%s", user, pwd, coode, machine_code, machine_code);
    return bsphp_send_raw(c, "login.lg", extra, out_resp);
}

/* registration.lg：注册账号（常用字段）。 */
int bsphp_register_lg(bsphp_client_t *c,
                      const char *user, const char *pwd, const char *pwdb,
                      const char *mobile, const char *qq, const char *mail,
                      const char *mibao_wenti, const char *mibao_daan,
                      const char *coode, const char *machine_code, const char *extension,
                      char **out_resp) {
    char extra[2048];
    snprintf(extra, sizeof(extra),
             "user=%s&pwd=%s&pwdb=%s&mobile=%s&qq=%s&mail=%s&mibao_wenti=%s&mibao_daan=%s&coode=%s&key=%s&extension=%s",
             user ? user : "", pwd ? pwd : "", pwdb ? pwdb : "",
             mobile ? mobile : "", qq ? qq : "", mail ? mail : "",
             mibao_wenti ? mibao_wenti : "", mibao_daan ? mibao_daan : "",
             coode ? coode : "", machine_code ? machine_code : "", extension ? extension : "");
    return bsphp_send_raw(c, "registration.lg", extra, out_resp);
}

/* cancellation.lg：账号注销。 */
int bsphp_logout_lg(bsphp_client_t *c, char **out_resp) {
    return bsphp_send_raw(c, "cancellation.lg", "", out_resp);
}

/* date.in：服务器时间。 */
int bsphp_get_server_date(bsphp_client_t *c, char **out_resp) {
    return bsphp_send_raw(c, "date.in", "", out_resp);
}

/* v.in：版本信息。 */
int bsphp_get_version(bsphp_client_t *c, char **out_resp) {
    return bsphp_send_raw(c, "v.in", "", out_resp);
}

/* imga.in：验证码信息。 */
int bsphp_get_captcha_info(bsphp_client_t *c, char **out_resp) {
    return bsphp_send_raw(c, "imga.in", "", out_resp);
}

/* getsetimag.in：验证码开关（type 可选，如 INGES_LOGIN）。 */
int bsphp_get_set_imag(bsphp_client_t *c, const char *type, char **out_resp) {
    char extra[512];
    if (type && type[0]) {
        snprintf(extra, sizeof(extra), "type=%s", type);
    } else {
        extra[0] = '\0';
    }
    return bsphp_send_raw(c, "getsetimag.in", extra, out_resp);
}

/* miao.in：软件描述。 */
int bsphp_get_soft_info(bsphp_client_t *c, char **out_resp) {
    return bsphp_send_raw(c, "miao.in", "", out_resp);
}

/* url.in：预设 URL。 */
int bsphp_get_preset_url(bsphp_client_t *c, char **out_resp) {
    return bsphp_send_raw(c, "url.in", "", out_resp);
}

/* weburl.in：Web URL。 */
int bsphp_get_web_url(bsphp_client_t *c, char **out_resp) {
    return bsphp_send_raw(c, "weburl.in", "", out_resp);
}

/* globalinfo.in：软件配置段。 */
int bsphp_get_global_info(bsphp_client_t *c, char **out_resp) {
    return bsphp_send_raw(c, "globalinfo.in", "", out_resp);
}

/* appcustom.in：自定义配置。 */
int bsphp_get_app_custom(bsphp_client_t *c, const char *info, char **out_resp) {
    char extra[512];
    snprintf(extra, sizeof(extra), "info=%s", info ? info : "");
    return bsphp_send_raw(c, "appcustom.in", extra, out_resp);
}

/* logica.in / logicb.in / logicinfoa.in / logicinfob.in。 */
int bsphp_get_logic_a(bsphp_client_t *c, char **out_resp) { return bsphp_send_raw(c, "logica.in", "", out_resp); }
int bsphp_get_logic_b(bsphp_client_t *c, char **out_resp) { return bsphp_send_raw(c, "logicb.in", "", out_resp); }
int bsphp_get_logic_info_a(bsphp_client_t *c, char **out_resp) { return bsphp_send_raw(c, "logicinfoa.in", "", out_resp); }
int bsphp_get_logic_info_b(bsphp_client_t *c, char **out_resp) { return bsphp_send_raw(c, "logicinfob.in", "", out_resp); }

/* vipdate.lg：账号到期时间。 */
int bsphp_get_end_time(bsphp_client_t *c, char **out_resp) {
    return bsphp_send_raw(c, "vipdate.lg", "", out_resp);
}

/* getuserinfo.lg：用户信息（info 可空，逗号分隔字段）。 */
int bsphp_get_user_info(bsphp_client_t *c, const char *info, char **out_resp) {
    char extra[512];
    if (info && info[0]) {
        snprintf(extra, sizeof(extra), "info=%s", info);
    } else {
        extra[0] = '\0';
    }
    return bsphp_send_raw(c, "getuserinfo.lg", extra, out_resp);
}

/* userkey.lg：用户绑定特征 key。 */
int bsphp_get_user_key(bsphp_client_t *c, char **out_resp) {
    return bsphp_send_raw(c, "userkey.lg", "", out_resp);
}

/* timeout.lg：登录心跳。 */
int bsphp_heartbeat_lg(bsphp_client_t *c, char **out_resp) {
    return bsphp_send_raw(c, "timeout.lg", "", out_resp);
}

/* 邮箱验证码相关。 */
int bsphp_send_email_code(bsphp_client_t *c, const char *scene, const char *email, const char *coode, char **out_resp) {
    char extra[1024];
    snprintf(extra, sizeof(extra), "scene=%s&email=%s&coode=%s",
             scene ? scene : "", email ? email : "", coode ? coode : "");
    return bsphp_send_raw(c, "send_email.lg", extra, out_resp);
}

int bsphp_register_email(bsphp_client_t *c, const char *user, const char *email, const char *email_code, const char *pwd, const char *pwdb, const char *key, const char *coode, char **out_resp) {
    char extra[2048];
    snprintf(extra, sizeof(extra), "user=%s&email=%s&email_code=%s&pwd=%s&pwdb=%s&key=%s&coode=%s",
             user ? user : "", email ? email : "", email_code ? email_code : "",
             pwd ? pwd : "", pwdb ? pwdb : "", key ? key : "", coode ? coode : "");
    return bsphp_send_raw(c, "register_email.lg", extra, out_resp);
}

int bsphp_login_email(bsphp_client_t *c, const char *email, const char *email_code, const char *key, const char *maxoror, const char *coode, char **out_resp) {
    char extra[2048];
    snprintf(extra, sizeof(extra), "email=%s&email_code=%s&key=%s&maxoror=%s&coode=%s",
             email ? email : "", email_code ? email_code : "",
             key ? key : "", maxoror ? maxoror : "", coode ? coode : "");
    return bsphp_send_raw(c, "login_email.lg", extra, out_resp);
}

int bsphp_reset_email_pwd(bsphp_client_t *c, const char *email, const char *email_code, const char *pwd, const char *pwdb, const char *coode, char **out_resp) {
    char extra[2048];
    snprintf(extra, sizeof(extra), "email=%s&email_code=%s&pwd=%s&pwdb=%s&coode=%s",
             email ? email : "", email_code ? email_code : "",
             pwd ? pwd : "", pwdb ? pwdb : "", coode ? coode : "");
    return bsphp_send_raw(c, "resetpwd_email.lg", extra, out_resp);
}

/* 短信验证码相关。 */
int bsphp_send_sms_code(bsphp_client_t *c, const char *scene, const char *mobile, const char *area, const char *coode, char **out_resp) {
    char extra[1024];
    snprintf(extra, sizeof(extra), "scene=%s&mobile=%s&area=%s&coode=%s",
             scene ? scene : "", mobile ? mobile : "", area ? area : "", coode ? coode : "");
    return bsphp_send_raw(c, "send_sms.lg", extra, out_resp);
}

int bsphp_register_sms(bsphp_client_t *c, const char *user, const char *mobile, const char *area, const char *sms_code, const char *pwd, const char *pwdb, const char *key, const char *coode, char **out_resp) {
    char extra[2048];
    snprintf(extra, sizeof(extra), "user=%s&mobile=%s&area=%s&sms_code=%s&pwd=%s&pwdb=%s&key=%s&coode=%s",
             user ? user : "", mobile ? mobile : "", area ? area : "", sms_code ? sms_code : "",
             pwd ? pwd : "", pwdb ? pwdb : "", key ? key : "", coode ? coode : "");
    return bsphp_send_raw(c, "register_sms.lg", extra, out_resp);
}

int bsphp_login_sms(bsphp_client_t *c, const char *mobile, const char *area, const char *sms_code, const char *key, const char *maxoror, const char *coode, char **out_resp) {
    char extra[2048];
    snprintf(extra, sizeof(extra), "mobile=%s&area=%s&sms_code=%s&key=%s&maxoror=%s&coode=%s",
             mobile ? mobile : "", area ? area : "", sms_code ? sms_code : "",
             key ? key : "", maxoror ? maxoror : "", coode ? coode : "");
    return bsphp_send_raw(c, "login_sms.lg", extra, out_resp);
}

int bsphp_reset_sms_pwd(bsphp_client_t *c, const char *mobile, const char *area, const char *sms_code, const char *pwd, const char *pwdb, const char *coode, char **out_resp) {
    char extra[2048];
    snprintf(extra, sizeof(extra), "mobile=%s&area=%s&sms_code=%s&pwd=%s&pwdb=%s&coode=%s",
             mobile ? mobile : "", area ? area : "", sms_code ? sms_code : "",
             pwd ? pwd : "", pwdb ? pwdb : "", coode ? coode : "");
    return bsphp_send_raw(c, "resetpwd_sms.lg", extra, out_resp);
}

/* 其他账号功能。 */
int bsphp_unbind_lg(bsphp_client_t *c, const char *user, const char *pwd, char **out_resp) {
    char extra[1024];
    snprintf(extra, sizeof(extra), "user=%s&pwd=%s", user ? user : "", pwd ? pwd : "");
    return bsphp_send_raw(c, "jiekey.lg", extra, out_resp);
}

int bsphp_pay_lg(bsphp_client_t *c, const char *user, const char *userpwd, int userset, const char *ka, const char *pwd, char **out_resp) {
    char extra[1024];
    snprintf(extra, sizeof(extra), "user=%s&userpwd=%s&userset=%s&ka=%s&pwd=%s",
             user ? user : "", userpwd ? userpwd : "", userset ? "1" : "0", ka ? ka : "", pwd ? pwd : "");
    return bsphp_send_raw(c, "chong.lg", extra, out_resp);
}

int bsphp_back_pass_lg(bsphp_client_t *c, const char *user, const char *pwd, const char *pwdb, const char *wenti, const char *daan, const char *coode, char **out_resp) {
    char extra[2048];
    snprintf(extra, sizeof(extra), "user=%s&pwd=%s&pwdb=%s&wenti=%s&daan=%s&coode=%s",
             user ? user : "", pwd ? pwd : "", pwdb ? pwdb : "",
             wenti ? wenti : "", daan ? daan : "", coode ? coode : "");
    return bsphp_send_raw(c, "backto.lg", extra, out_resp);
}

int bsphp_edit_pass_lg(bsphp_client_t *c, const char *user, const char *pwd, const char *pwda, const char *pwdb, const char *img, char **out_resp) {
    char extra[2048];
    snprintf(extra, sizeof(extra), "user=%s&pwd=%s&pwda=%s&pwdb=%s&img=%s",
             user ? user : "", pwd ? pwd : "", pwda ? pwda : "", pwdb ? pwdb : "", img ? img : "");
    return bsphp_send_raw(c, "password.lg", extra, out_resp);
}

int bsphp_feedback_lg(bsphp_client_t *c, const char *user, const char *pwd, const char *table, const char *qq, const char *leix, const char *txt, const char *coode, char **out_resp) {
    char extra[2048];
    snprintf(extra, sizeof(extra), "user=%s&pwd=%s&table=%s&qq=%s&leix=%s&txt=%s&coode=%s",
             user ? user : "", pwd ? pwd : "", table ? table : "",
             qq ? qq : "", leix ? leix : "", txt ? txt : "", coode ? coode : "");
    return bsphp_send_raw(c, "liuyan.in", extra, out_resp);
}

/* 通用接口：api=接口名，extra_query="k1=v1&k2=v2"。 */
int bsphp_api_call(bsphp_client_t *c, const char *api, const char *extra_query, char **out_resp) {
    if (!c || !api || !out_resp) return 0;
    return bsphp_send_raw(c, api, (extra_query ? extra_query : ""), out_resp);
}
