* tar xzf utvpn-src-unix-v101-7101-public-2010.06.27.tar.gz
[lab.git] / utvpn / utvpn-unix-v101-7101-public / src / Cedar / Client.c
diff --git a/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Client.c b/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Client.c
new file mode 100644 (file)
index 0000000..40c67ab
--- /dev/null
@@ -0,0 +1,9916 @@
+// SoftEther UT-VPN SourceCode\r
+// \r
+// Copyright (C) 2004-2010 SoftEther Corporation.\r
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.\r
+// Copyright (C) 2003-2010 Daiyuu Nobori.\r
+// All Rights Reserved.\r
+// \r
+// http://utvpn.tsukuba.ac.jp/\r
+// \r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// version 2 as published by the Free Software Foundation.\r
+// \r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+// GNU General Public License for more details.\r
+// \r
+// You should have received a copy of the GNU General Public License version 2\r
+// along with this program; if not, write to the Free Software\r
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\r
+// \r
+// このファイルは GPL バージョン 2 ライセンスで公開されています。\r
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布\r
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示\r
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の\r
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。\r
+// \r
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の\r
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )\r
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって\r
+// ホストされています。\r
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、\r
+// および、試験または研究のために利用が行われることを想定して配布\r
+// しています。\r
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に\r
+// あります。\r
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード\r
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して\r
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して\r
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース\r
+// に組み込みさせていただきます。\r
+// \r
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する\r
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。\r
+// \r
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社\r
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。\r
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの\r
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意\r
+// ください。\r
+// \r
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の\r
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、\r
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの\r
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社\r
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、\r
+// 公益保護にご協力いただきますようお願い申し上げます。\r
+// \r
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を\r
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客\r
+// を保護するための努力を行います。\r
+// \r
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/\r
+// 日本国内の脆弱性情報届出受付公的機関:\r
+//         独立行政法人 情報処理推進機構\r
+//         http://www.ipa.go.jp/security/vuln/report/\r
+// \r
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。\r
+// 連絡先: http://www.softether.co.jp/jp/contact/\r
+\r
+// -----------------------------------------------\r
+// [ChangeLog]\r
+// 2010.05.20\r
+//  新規リリース by SoftEther\r
+// -----------------------------------------------\r
+\r
+// Client.c\r
+// クライアントマネージャ\r
+\r
+#include "CedarPch.h"\r
+\r
+static CLIENT *client = NULL;\r
+static LISTENER *cn_listener = NULL;\r
+static LOCK *cn_listener_lock = NULL;\r
+static UINT64 cn_next_allow = 0;\r
+\r
+#ifdef OS_WIN32\r
+\r
+#endif // OS_WIN32\r
+\r
+// 注意: VPN Client サービスを実装するこのソースコードの一部には、\r
+// リエントラント (Reentrant: 再入可能) でないコードが含まれている。\r
+// もともと VPN Client のサービスと GUI (クライアント接続マネージャ) は一体\r
+// のものとして開発され、途中で分離された。その際に本来であれば TLS 等を用いて\r
+// スレッドセーフにしなければならない部分が、もとのままになってしまっている。\r
+// したがって、ごくまれに、GUI (クライアント接続マネージャ) や utvpncmd が\r
+// 複数個、1 個の VPN Client サービスに対して接続して、ほぼ同時に何らかの\r
+// 内部状態を変化させる処理を行ったとき、戻り値に不整合が生じる場合がある。\r
+\r
+// RPC_CLIENT_ENUM_ACCOUNT_ITEM を最終接続日時で逆ソート\r
+int CiCompareClientAccountEnumItemByLastConnectDateTime(void *p1, void *p2)\r
+{\r
+       RPC_CLIENT_ENUM_ACCOUNT_ITEM *a1, *a2;\r
+       if (p1 == NULL || p2 == NULL)\r
+       {\r
+               return 0;\r
+       }\r
+       a1 = *(RPC_CLIENT_ENUM_ACCOUNT_ITEM **)p1;\r
+       a2 = *(RPC_CLIENT_ENUM_ACCOUNT_ITEM **)p2;\r
+       if (a1 == NULL || a2 == NULL)\r
+       {\r
+               return 0;\r
+       }\r
+       if (a1->LastConnectDateTime > a2->LastConnectDateTime)\r
+       {\r
+               return -1;\r
+       }\r
+       else if (a1->LastConnectDateTime < a2->LastConnectDateTime)\r
+       {\r
+               return 1;\r
+       }\r
+\r
+       return 0;\r
+}\r
+\r
+// マシンが変更されていた場合はすべての仮想 LAN カードの MAC アドレスを乱数に設定する\r
+// このあたりは急いで実装したのでコードがあまり美しくない。\r
+// Q. なぜこのような処理が必要なのか?\r
+// A. Windows をインストールし、次に VPN Client をインストールして仮想 LAN カード\r
+//    を作成した状態を初期状態として HDD イメージをクローンし社内の複数の PC に\r
+//    インストールするような企業が存在する。\r
+//    そのような企業においてクローン後も仮想 LAN カードの MAC アドレスがすべて同一\r
+//    であれば障害の理由になる可能性があるためである。\r
+void CiChangeAllVLanMacAddressIfMachineChanged(CLIENT *c)\r
+{\r
+       UCHAR current_hash[SHA1_SIZE];\r
+       UCHAR current_hash_old[SHA1_SIZE];\r
+       UCHAR saved_hash[SHA1_SIZE];\r
+       // 引数チェック\r
+       if (c == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+#ifdef OS_WIN32\r
+       if (MsIsAdmin() == false)\r
+       {\r
+               return;\r
+       }\r
+#endif\r
+\r
+       // このあたりは急いで実装したのでコードがあまり美しくない。\r
+       CiGetCurrentMachineHash(current_hash);\r
+       CiGetCurrentMachineHashOld(current_hash_old);\r
+\r
+       if (CiReadLastMachineHash(saved_hash) == false)\r
+       {\r
+               CiWriteLastMachineHash(current_hash);\r
+               return;\r
+       }\r
+\r
+       if (Cmp(saved_hash, current_hash_old, SHA1_SIZE) == 0)\r
+       {\r
+               CiWriteLastMachineHash(current_hash);\r
+               return;\r
+       }\r
+\r
+       if (Cmp(saved_hash, current_hash, SHA1_SIZE) == 0)\r
+       {\r
+               return;\r
+       }\r
+\r
+       if (CiWriteLastMachineHash(current_hash) == false)\r
+       {\r
+               return;\r
+       }\r
+\r
+       CiChangeAllVLanMacAddress(c);\r
+}\r
+\r
+// 現在のマシンハッシュを取得する (古い方式)\r
+// このあたりは急いで実装したのでコードがあまり美しくない。\r
+void CiGetCurrentMachineHashOld(void *data)\r
+{\r
+       char name[MAX_PATH];\r
+       char *product_id = NULL;\r
+       // 引数チェック\r
+       if (data == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+#ifdef OS_WIN32\r
+       // プロダクト ID\r
+       product_id = MsRegReadStr(REG_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", "ProductId");\r
+       if (product_id == NULL)\r
+       {\r
+               product_id = MsRegReadStr(REG_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion", "ProductId");\r
+       }\r
+\r
+       StrCpy(name, sizeof(name), product_id);\r
+\r
+       Free(product_id);\r
+\r
+#else  // OS_WIN32\r
+       GetMachineName(name, sizeof(name));\r
+#endif // OS_WIN32\r
+\r
+       Trim(name);\r
+       StrUpper(name);\r
+\r
+       Hash(data, name, StrLen(name), true);\r
+}\r
+\r
+// 現在のマシンハッシュを取得する\r
+void CiGetCurrentMachineHash(void *data)\r
+{\r
+       char name[MAX_PATH];\r
+       char *product_id = NULL;\r
+       // 引数チェック\r
+       if (data == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       GetMachineName(name, sizeof(name));\r
+\r
+       Trim(name);\r
+       StrUpper(name);\r
+\r
+       Hash(data, name, StrLen(name), true);\r
+}\r
+\r
+// マシンハッシュを書き込む\r
+bool CiWriteLastMachineHash(void *data)\r
+{\r
+       // 引数チェック\r
+       if (data == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+#ifdef OS_WIN32\r
+       if (MsRegWriteBinEx(REG_LOCAL_MACHINE, MS_REG_TCP_SETTING_KEY, "LastMachineHash_UTVPNClient", data, SHA1_SIZE, true) == false)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       return true;\r
+#else  // OS_WIN32\r
+       return false;\r
+#endif // OS_WIN32\r
+}\r
+\r
+// 前回のマシンハッシュを取得する\r
+bool CiReadLastMachineHash(void *data)\r
+{\r
+       BUF *b = NULL;\r
+       // 引数チェック\r
+       if (data == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+#ifdef OS_WIN32\r
+       b = MsRegReadBinEx(REG_LOCAL_MACHINE, MS_REG_TCP_SETTING_KEY, "LastMachineHash_UTVPNClient", true);\r
+       if (b == NULL)\r
+       {\r
+               return false;\r
+       }\r
+       if (b->Size == SHA1_SIZE)\r
+       {\r
+               Copy(data, b->Buf, b->Size);\r
+               FreeBuf(b);\r
+\r
+               return true;\r
+       }\r
+\r
+       FreeBuf(b);\r
+       return false;\r
+#else  // OS_WIN32\r
+       return false;\r
+#endif // OS_WIN32\r
+}\r
+\r
+// すべての仮想 LAN カードの MAC アドレスを乱数に設定する\r
+void CiChangeAllVLanMacAddress(CLIENT *c)\r
+{\r
+       RPC_CLIENT_ENUM_VLAN t;\r
+       // 引数チェック\r
+       if (c == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Zero(&t, sizeof(t));\r
+       if (CtEnumVLan(c, &t))\r
+       {\r
+               UINT i;\r
+\r
+               for (i = 0;i < t.NumItem;i++)\r
+               {\r
+                       RPC_CLIENT_ENUM_VLAN_ITEM *e = t.Items[i];\r
+                       UCHAR mac[6];\r
+\r
+                       if (StrToMac(mac, e->MacAddress) && mac[1] == 0xAC)\r
+                       {\r
+                               char *name = e->DeviceName;\r
+                               RPC_CLIENT_SET_VLAN s;\r
+                               UCHAR mac[6];\r
+\r
+                               GenMacAddress(mac);\r
+\r
+                               Zero(&s, sizeof(s));\r
+                               StrCpy(s.DeviceName, sizeof(s.DeviceName), name);\r
+\r
+                               MacToStr(s.MacAddress, sizeof(s.MacAddress), mac);\r
+\r
+                               CtSetVLan(c, &s);\r
+                       }\r
+               }\r
+\r
+               CiFreeClientEnumVLan(&t);\r
+       }\r
+}\r
+\r
+// 通知サービスの準備が完了するまで待機する\r
+void CnWaitForCnServiceReady()\r
+{\r
+       UINT64 start_time = Tick64();\r
+\r
+       while ((start_time + (UINT64)CLIENT_WAIT_CN_READY_TIMEOUT) >= Tick64())\r
+       {\r
+               if (CnIsCnServiceReady())\r
+               {\r
+                       break;\r
+               }\r
+\r
+               SleepThread(100);\r
+       }\r
+}\r
+\r
+// 通知サービスの準備が完了しているかどうかチェックする\r
+// このあたりは急いで実装したのでコードがあまり美しくない。\r
+bool CnIsCnServiceReady()\r
+{\r
+       SOCK *s;\r
+       // 通知サービスの起動を確認する\r
+       if (CnCheckAlreadyExists(false) == false)\r
+       {\r
+               // 起動していない\r
+               return false;\r
+       }\r
+\r
+       // TCP ポートへの接続を試行する\r
+       s = ConnectEx("localhost", CLIENT_NOTIFY_PORT, 500);\r
+       if (s == NULL)\r
+       {\r
+               // TCP ポートを開いていない\r
+               return false;\r
+       }\r
+\r
+       Disconnect(s);\r
+       ReleaseSock(s);\r
+\r
+       // 起動していた\r
+       return true;\r
+}\r
+\r
+// すでに通知サービスが動作しているかどうかチェックする\r
+bool CnCheckAlreadyExists(bool lock)\r
+{\r
+       bool ret = false;\r
+\r
+#ifdef OS_WIN32\r
+       ret = Win32CnCheckAlreadyExists(lock);\r
+#endif\r
+\r
+       return ret;\r
+}\r
+\r
+typedef struct CNC_STATUS_PRINTER_WINDOW_PARAM\r
+{\r
+       THREAD *Thread;\r
+       SESSION *Session;\r
+       SOCK *Sock;\r
+} CNC_STATUS_PRINTER_WINDOW_PARAM;\r
+\r
+typedef struct CNC_CONNECT_ERROR_DLG_THREAD_PARAM\r
+{\r
+       SESSION *Session;\r
+       SOCK *Sock;\r
+       bool HaltThread;\r
+       EVENT *Event;\r
+} CNC_CONNECT_ERROR_DLG_THREAD_PARAM;\r
+\r
+\r
+// Win32 における utvpnclient.exe のファイル名を取得する\r
+char *CiGetVpnClientExeFileName()\r
+{\r
+       if (Is64() == false)\r
+       {\r
+               return CLIENT_WIN32_EXE_FILENAME;\r
+       }\r
+       else\r
+       {\r
+               if (IsX64())\r
+               {\r
+                       return CLIENT_WIN32_EXE_FILENAME_X64;\r
+               }\r
+               else\r
+               {\r
+                       return CLIENT_WIN32_EXE_FILENAME_IA64;\r
+               }\r
+       }\r
+}\r
+\r
+// 証明書チェックダイアログクライアント強制停止用スレッド\r
+void CncCheckCertHaltThread(THREAD *thread, void *param)\r
+{\r
+       CNC_CONNECT_ERROR_DLG_THREAD_PARAM *dp = (CNC_CONNECT_ERROR_DLG_THREAD_PARAM *)param;\r
+       // 引数チェック\r
+       if (thread == NULL || param == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       while (true)\r
+       {\r
+               if (dp->Session->Halt || dp->HaltThread)\r
+               {\r
+                       break;\r
+               }\r
+\r
+               Wait(dp->Event, 100);\r
+       }\r
+\r
+       Disconnect(dp->Sock);\r
+}\r
+\r
+// 証明書チェックダイアログの表示\r
+void CncCheckCert(SESSION *session, UI_CHECKCERT *dlg)\r
+{\r
+       SOCK *s;\r
+       PACK *p;\r
+       CNC_CONNECT_ERROR_DLG_THREAD_PARAM *dp;\r
+       THREAD *t;\r
+       // 引数チェック\r
+       if (dlg == NULL || session == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       s = CncConnect();\r
+       if (s == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       p = NewPack();\r
+       PackAddStr(p, "function", "check_cert");\r
+       PackAddUniStr(p, "AccountName", dlg->AccountName);\r
+       PackAddStr(p, "ServerName", dlg->ServerName);\r
+       PackAddX(p, "x", dlg->x);\r
+       PackAddX(p, "parent_x", dlg->parent_x);\r
+       PackAddX(p, "old_x", dlg->old_x);\r
+       PackAddBool(p, "DiffWarning", dlg->DiffWarning);\r
+       PackAddBool(p, "Ok", dlg->Ok);\r
+       PackAddBool(p, "SaveServerCert", dlg->SaveServerCert);\r
+\r
+       SendPack(s, p);\r
+       FreePack(p);\r
+\r
+       dp = ZeroMalloc(sizeof(CNC_CONNECT_ERROR_DLG_THREAD_PARAM));\r
+       dp->Sock = s;\r
+       dp->Event = NewEvent();\r
+       dp->Session = session;\r
+\r
+       t = NewThread(CncCheckCertHaltThread, dp);\r
+\r
+       p = RecvPack(s);\r
+       if (p != NULL)\r
+       {\r
+               dlg->Ok = PackGetBool(p, "Ok");\r
+               dlg->DiffWarning = PackGetBool(p, "DiffWarning");\r
+               dlg->SaveServerCert = PackGetBool(p, "SaveServerCert");\r
+\r
+               FreePack(p);\r
+       }\r
+\r
+       dp->HaltThread = true;\r
+       Set(dp->Event);\r
+\r
+       WaitThread(t, INFINITE);\r
+\r
+       ReleaseEvent(dp->Event);\r
+       Free(dp);\r
+       ReleaseThread(t);\r
+\r
+       Disconnect(s);\r
+       ReleaseSock(s);\r
+}\r
+\r
+// スマートカード署名ダイアログ\r
+bool CncSecureSignDlg(SECURE_SIGN *sign)\r
+{\r
+       SOCK *s;\r
+       PACK *p;\r
+       bool ret = false;\r
+       // 引数チェック\r
+       if (sign == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       s = CncConnect();\r
+       if (s == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       p = NewPack();\r
+       PackAddStr(p, "function", "secure_sign");\r
+       OutRpcSecureSign(p, sign);\r
+\r
+       SendPack(s, p);\r
+       FreePack(p);\r
+\r
+       p = RecvPack(s);\r
+       if (p != NULL)\r
+       {\r
+               ret = PackGetBool(p, "ret");\r
+\r
+               if (ret)\r
+               {\r
+                       FreeRpcSecureSign(sign);\r
+\r
+                       Zero(sign, sizeof(SECURE_SIGN));\r
+                       InRpcSecureSign(sign, p);\r
+               }\r
+\r
+               FreePack(p);\r
+       }\r
+\r
+       Disconnect(s);\r
+       ReleaseSock(s);\r
+\r
+       return ret;\r
+}\r
+\r
+// NIC 情報ダイアログの表示\r
+SOCK *CncNicInfo(UI_NICINFO *info)\r
+{\r
+       SOCK *s;\r
+       PACK *p;\r
+       bool ret = false;\r
+       // 引数チェック\r
+       if (info == NULL)\r
+       {\r
+               return NULL;\r
+       }\r
+\r
+       s = CncConnectEx(200);\r
+       if (s == NULL)\r
+       {\r
+               return NULL;\r
+       }\r
+\r
+       p = NewPack();\r
+       PackAddStr(p, "function", "nicinfo");\r
+       PackAddStr(p, "NicName", info->NicName);\r
+       PackAddUniStr(p, "AccountName", info->AccountName);\r
+\r
+       SendPack(s, p);\r
+       FreePack(p);\r
+\r
+       return s;\r
+}\r
+\r
+// NIC 情報ダイアログを閉じる\r
+void CncNicInfoFree(SOCK *s)\r
+{\r
+       // 引数チェック\r
+       if (s == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Disconnect(s);\r
+       ReleaseSock(s);\r
+}\r
+\r
+// メッセージダイアログの表示\r
+SOCK *CncMsgDlg(UI_MSG_DLG *dlg)\r
+{\r
+       SOCK *s;\r
+       PACK *p;\r
+       bool ret = false;\r
+       char *utf;\r
+       // 引数チェック\r
+       if (dlg == NULL)\r
+       {\r
+               return NULL;\r
+       }\r
+\r
+       s = CncConnectEx(200);\r
+       if (s == NULL)\r
+       {\r
+               return NULL;\r
+       }\r
+\r
+       p = NewPack();\r
+       PackAddStr(p, "function", "msg_dialog");\r
+       PackAddStr(p, "ServerName", dlg->ServerName);\r
+       PackAddStr(p, "HubName", dlg->HubName);\r
+       utf = CopyUniToUtf(dlg->Msg);\r
+       PackAddData(p, "Msg", utf, StrLen(utf));\r
+       Free(utf);\r
+\r
+       SendPack(s, p);\r
+       FreePack(p);\r
+\r
+       return s;\r
+}\r
+\r
+// メッセージダイアログを閉じる\r
+void CndMsgDlgFree(SOCK *s)\r
+{\r
+       // 引数チェック\r
+       if (s == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Disconnect(s);\r
+       ReleaseSock(s);\r
+}\r
+\r
+// パスワード入力ダイアログクライアント強制停止用スレッド\r
+void CncPasswordDlgHaltThread(THREAD *thread, void *param)\r
+{\r
+       CNC_CONNECT_ERROR_DLG_THREAD_PARAM *dp = (CNC_CONNECT_ERROR_DLG_THREAD_PARAM *)param;\r
+       // 引数チェック\r
+       if (thread == NULL || param == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       while (true)\r
+       {\r
+               if (dp->Session->Halt || dp->HaltThread)\r
+               {\r
+                       break;\r
+               }\r
+\r
+               Wait(dp->Event, 100);\r
+       }\r
+\r
+       Disconnect(dp->Sock);\r
+}\r
+\r
+// パスワード入力ダイアログの表示\r
+bool CncPasswordDlg(SESSION *session, UI_PASSWORD_DLG *dlg)\r
+{\r
+       SOCK *s;\r
+       PACK *p;\r
+       CNC_CONNECT_ERROR_DLG_THREAD_PARAM *dp;\r
+       THREAD *t;\r
+       bool ret = false;\r
+       // 引数チェック\r
+       if (dlg == NULL || session == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       s = CncConnect();\r
+       if (s == NULL)\r
+       {\r
+               Wait(session->HaltEvent, session->RetryInterval);\r
+               return true;\r
+       }\r
+\r
+       p = NewPack();\r
+       PackAddStr(p, "function", "password_dialog");\r
+       PackAddInt(p, "Type", dlg->Type);\r
+       PackAddStr(p, "Username", dlg->Username);\r
+       PackAddStr(p, "Password", dlg->Password);\r
+       PackAddStr(p, "ServerName", dlg->ServerName);\r
+       PackAddInt(p, "RetryIntervalSec", dlg->RetryIntervalSec);\r
+       PackAddBool(p, "ProxyServer", dlg->ProxyServer);\r
+       PackAddBool(p, "AdminMode", dlg->AdminMode);\r
+       PackAddBool(p, "ShowNoSavePassword", dlg->ShowNoSavePassword);\r
+       PackAddBool(p, "NoSavePassword", dlg->NoSavePassword);\r
+\r
+       SendPack(s, p);\r
+       FreePack(p);\r
+\r
+       dp = ZeroMalloc(sizeof(CNC_CONNECT_ERROR_DLG_THREAD_PARAM));\r
+       dp->Session = session;\r
+       dp->Sock = s;\r
+       dp->Event = NewEvent();\r
+\r
+       t = NewThread(CncConnectErrorDlgHaltThread, dp);\r
+\r
+       p = RecvPack(s);\r
+       if (p != NULL)\r
+       {\r
+               ret = PackGetBool(p, "ok");\r
+               dlg->NoSavePassword = PackGetBool(p, "NoSavePassword");\r
+               dlg->ProxyServer = PackGetBool(p, "ProxyServer");\r
+               dlg->Type = PackGetInt(p, "Type");\r
+               PackGetStr(p, "Username", dlg->Username, sizeof(dlg->Username));\r
+               PackGetStr(p, "Password", dlg->Password, sizeof(dlg->Password));\r
+\r
+               FreePack(p);\r
+       }\r
+\r
+       dp->HaltThread = true;\r
+       Set(dp->Event);\r
+\r
+       WaitThread(t, INFINITE);\r
+\r
+       ReleaseEvent(dp->Event);\r
+       Free(dp);\r
+       ReleaseThread(t);\r
+\r
+       Disconnect(s);\r
+       ReleaseSock(s);\r
+\r
+       return ret;\r
+}\r
+\r
+// 接続エラーダイアログクライアント強制停止用スレッド\r
+void CncConnectErrorDlgHaltThread(THREAD *thread, void *param)\r
+{\r
+       CNC_CONNECT_ERROR_DLG_THREAD_PARAM *dp = (CNC_CONNECT_ERROR_DLG_THREAD_PARAM *)param;\r
+       // 引数チェック\r
+       if (thread == NULL || param == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       while (true)\r
+       {\r
+               if (dp->Session->Halt || dp->HaltThread)\r
+               {\r
+                       break;\r
+               }\r
+\r
+               Wait(dp->Event, 100);\r
+       }\r
+\r
+       Disconnect(dp->Sock);\r
+}\r
+\r
+// 接続エラーダイアログの表示\r
+bool CncConnectErrorDlg(SESSION *session, UI_CONNECTERROR_DLG *dlg)\r
+{\r
+       SOCK *s;\r
+       PACK *p;\r
+       CNC_CONNECT_ERROR_DLG_THREAD_PARAM *dp;\r
+       THREAD *t;\r
+       bool ret = false;\r
+       // 引数チェック\r
+       if (dlg == NULL || session == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       s = CncConnect();\r
+       if (s == NULL)\r
+       {\r
+               Wait(session->HaltEvent, session->RetryInterval);\r
+               return true;\r
+       }\r
+\r
+       p = NewPack();\r
+       PackAddStr(p, "function", "connecterror_dialog");\r
+       PackAddUniStr(p, "AccountName", dlg->AccountName);\r
+       PackAddStr(p, "ServerName", dlg->ServerName);\r
+       PackAddInt(p, "Err", dlg->Err);\r
+       PackAddInt(p, "CurrentRetryCount", dlg->CurrentRetryCount);\r
+       PackAddInt(p, "RetryLimit", dlg->RetryLimit);\r
+       PackAddInt(p, "RetryIntervalSec", dlg->RetryIntervalSec);\r
+       PackAddBool(p, "HideWindow", dlg->HideWindow);\r
+\r
+       SendPack(s, p);\r
+       FreePack(p);\r
+\r
+       dp = ZeroMalloc(sizeof(CNC_CONNECT_ERROR_DLG_THREAD_PARAM));\r
+       dp->Session = session;\r
+       dp->Sock = s;\r
+       dp->Event = NewEvent();\r
+\r
+       t = NewThread(CncConnectErrorDlgHaltThread, dp);\r
+\r
+       p = RecvPack(s);\r
+       if (p != NULL)\r
+       {\r
+               ret = PackGetBool(p, "ok");\r
+               dlg->HideWindow = PackGetBool(p, "HideWindow");\r
+\r
+               FreePack(p);\r
+       }\r
+\r
+       dp->HaltThread = true;\r
+       Set(dp->Event);\r
+\r
+       WaitThread(t, INFINITE);\r
+\r
+       ReleaseEvent(dp->Event);\r
+       Free(dp);\r
+       ReleaseThread(t);\r
+\r
+       Disconnect(s);\r
+       ReleaseSock(s);\r
+\r
+       return ret;\r
+}\r
+\r
+// ステータス表示器クライアント用スレッド\r
+void CncStatusPrinterWindowThreadProc(THREAD *thread, void *param)\r
+{\r
+       CNC_STATUS_PRINTER_WINDOW_PARAM *pp;\r
+       SOCK *sock;\r
+       PACK *p;\r
+       // 引数チェック\r
+       if (thread == NULL || param == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       pp = (CNC_STATUS_PRINTER_WINDOW_PARAM *)param;\r
+       sock = pp->Sock;\r
+       pp->Thread = thread;\r
+       AddRef(pp->Thread->ref);\r
+\r
+       NoticeThreadInit(thread);\r
+\r
+       p = RecvPack(sock);\r
+       if (p != NULL)\r
+       {\r
+               // セッションを停止する\r
+               StopSessionEx(pp->Session, true);\r
+\r
+               FreePack(p);\r
+       }\r
+}\r
+\r
+// ステータス表示器クライアントの作成\r
+SOCK *CncStatusPrinterWindowStart(SESSION *s)\r
+{\r
+       SOCK *sock;\r
+       PACK *p;\r
+       THREAD *t;\r
+       CNC_STATUS_PRINTER_WINDOW_PARAM *param;\r
+       // 引数チェック\r
+       if (s == NULL)\r
+       {\r
+               return NULL;\r
+       }\r
+\r
+       sock = CncConnect();\r
+\r
+       if (sock == NULL)\r
+       {\r
+               return NULL;\r
+       }\r
+\r
+       p = NewPack();\r
+       PackAddStr(p, "function", "status_printer");\r
+       PackAddUniStr(p, "account_name", s->Account->ClientOption->AccountName);\r
+\r
+       if (SendPack(sock, p) == false)\r
+       {\r
+               FreePack(p);\r
+               ReleaseSock(sock);\r
+\r
+               return NULL;\r
+       }\r
+\r
+       FreePack(p);\r
+\r
+       param = ZeroMalloc(sizeof(CNC_STATUS_PRINTER_WINDOW_PARAM));\r
+       param->Sock = sock;\r
+       param->Session = s;\r
+\r
+       sock->Param = param;\r
+\r
+       t = NewThread(CncStatusPrinterWindowThreadProc, param);\r
+       WaitThreadInit(t);\r
+\r
+       ReleaseThread(t);\r
+\r
+       return sock;\r
+}\r
+\r
+// ステータス表示器に対して文字列を送信\r
+void CncStatusPrinterWindowPrint(SOCK *s, wchar_t *str)\r
+{\r
+       CNC_STATUS_PRINTER_WINDOW_PARAM *param;\r
+       PACK *p;\r
+       // 引数チェック\r
+       if (s == NULL || str == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       param = (CNC_STATUS_PRINTER_WINDOW_PARAM *)s->Param;\r
+\r
+       p = NewPack();\r
+       PackAddUniStr(p, "string", str);\r
+       SendPack(s, p);\r
+       FreePack(p);\r
+}\r
+\r
+// ステータス表示器クライアントの停止\r
+void CncStatusPrinterWindowStop(SOCK *s)\r
+{\r
+       CNC_STATUS_PRINTER_WINDOW_PARAM *param;\r
+       // 引数チェック\r
+       if (s == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       param = (CNC_STATUS_PRINTER_WINDOW_PARAM *)s->Param;\r
+\r
+       // クライアントソケット切断\r
+       Disconnect(s);\r
+\r
+       // スレッド終了\r
+       WaitThread(param->Thread, INFINITE);\r
+       ReleaseThread(param->Thread);\r
+\r
+       Free(param);\r
+       ReleaseSock(s);\r
+}\r
+\r
+// Windows Vista 用のドライバインストーラの起動\r
+bool CncExecDriverInstaller(char *arg)\r
+{\r
+       SOCK *s = CncConnect();\r
+       PACK *p;\r
+       bool ret;\r
+       if (s == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       p = NewPack();\r
+       PackAddStr(p, "function", "exec_driver_installer");\r
+       PackAddStr(p, "arg", arg);\r
+\r
+       SendPack(s, p);\r
+       FreePack(p);\r
+\r
+       p = RecvPack(s);\r
+       if (p == NULL)\r
+       {\r
+               Disconnect(s);\r
+               ReleaseSock(s);\r
+               return false;\r
+       }\r
+\r
+       ret = PackGetBool(p, "ret");\r
+\r
+       FreePack(p);\r
+\r
+       Disconnect(s);\r
+       ReleaseSock(s);\r
+\r
+       return ret;\r
+}\r
+\r
+// 現在動作しているクライアント通知サービスにソケットを解放させる\r
+void CncReleaseSocket()\r
+{\r
+       SOCK *s = CncConnect();\r
+       PACK *p;\r
+       if (s == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       p = NewPack();\r
+       PackAddStr(p, "function", "release_socket");\r
+\r
+#ifdef OS_WIN32\r
+       PackAddInt(p, "pid", MsGetProcessId());\r
+#endif // OS_WIN32\r
+\r
+       SendPack(s, p);\r
+       FreePack(p);\r
+\r
+       Disconnect(s);\r
+       ReleaseSock(s);\r
+}\r
+\r
+// クライアント通知サービスのセッション ID の取得\r
+UINT CncGetSessionId()\r
+{\r
+       SOCK *s = CncConnect();\r
+       PACK *p;\r
+       UINT ret;\r
+       if (s == NULL)\r
+       {\r
+               return INFINITE;\r
+       }\r
+\r
+       p = NewPack();\r
+       PackAddStr(p, "function", "get_session_id");\r
+\r
+       SendPack(s, p);\r
+       FreePack(p);\r
+\r
+       p = RecvPack(s);\r
+       if (p == NULL)\r
+       {\r
+               Disconnect(s);\r
+               ReleaseSock(s);\r
+               return INFINITE;\r
+       }\r
+\r
+       ret = PackGetInt(p, "session_id");\r
+\r
+       FreePack(p);\r
+\r
+       Disconnect(s);\r
+       ReleaseSock(s);\r
+\r
+       return ret;\r
+}\r
+\r
+// クライアント通知サービスのプロセスの終了\r
+void CncExit()\r
+{\r
+       SOCK *s = CncConnectEx(256);\r
+       PACK *p;\r
+       if (s != NULL)\r
+       {\r
+               p = NewPack();\r
+               PackAddStr(p, "function", "exit");\r
+\r
+               SendPack(s, p);\r
+\r
+               FreePack(p);\r
+\r
+               FreePack(RecvPack(s));\r
+\r
+               Disconnect(s);\r
+               ReleaseSock(s);\r
+       }\r
+\r
+#ifdef OS_WIN32\r
+       MsKillOtherInstanceEx("utvpnclient");\r
+#endif // OS_WIN32\r
+}\r
+\r
+// クライアント通知サービスへの接続\r
+SOCK *CncConnect()\r
+{\r
+       return CncConnectEx(0);\r
+}\r
+SOCK *CncConnectEx(UINT timeout)\r
+{\r
+       SOCK *s = ConnectEx("localhost", CLIENT_NOTIFY_PORT, timeout);\r
+\r
+       return s;\r
+}\r
+\r
+#ifdef OS_WIN32\r
+\r
+// 証明書チェックダイアログ用スレッド\r
+void Win32CnCheckCertThreadProc(THREAD *thread, void *param)\r
+{\r
+       UI_CHECKCERT *dlg;\r
+       // 引数チェック\r
+       if (thread == NULL || param == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       dlg = (UI_CHECKCERT *)param;\r
+\r
+       CheckCertDlg(dlg);\r
+       {\r
+               PACK *p = NewPack();\r
+\r
+               PackAddBool(p, "Ok", dlg->Ok);\r
+               PackAddBool(p, "SaveServerCert", dlg->SaveServerCert);\r
+\r
+               SendPack(dlg->Sock, p);\r
+               FreePack(p);\r
+\r
+               FreePack(RecvPack(dlg->Sock));\r
+       }\r
+\r
+       Disconnect(dlg->Sock);\r
+}\r
+\r
+// 証明書チェックダイアログ\r
+void Win32CnCheckCert(SOCK *s, PACK *p)\r
+{\r
+       UI_CHECKCERT dlg;\r
+       THREAD *t;\r
+       Zero(&dlg, sizeof(dlg));\r
+       // 引数チェック\r
+       if (s == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       PackGetUniStr(p, "AccountName", dlg.AccountName, sizeof(dlg.AccountName));\r
+       PackGetStr(p, "ServerName", dlg.ServerName, sizeof(dlg.ServerName));\r
+       dlg.x = PackGetX(p, "x");\r
+       dlg.parent_x = PackGetX(p, "parent_x");\r
+       dlg.old_x = PackGetX(p, "old_x");\r
+       dlg.DiffWarning = PackGetBool(p, "DiffWarning");\r
+       dlg.Ok = PackGetBool(p, "Ok");\r
+       dlg.SaveServerCert = PackGetBool(p, "SaveServerCert");\r
+       dlg.Sock = s;\r
+\r
+       t = NewThread(Win32CnCheckCertThreadProc, &dlg);\r
+\r
+       FreePack(RecvPack(s));\r
+\r
+       dlg.Halt = true;\r
+\r
+       WaitThread(t, INFINITE);\r
+       ReleaseThread(t);\r
+\r
+       FreeX(dlg.parent_x);\r
+       FreeX(dlg.old_x);\r
+       FreeX(dlg.x);\r
+}\r
+\r
+// メッセージ表示ダイアログスレッドプロシージャ\r
+void Win32CnMsgDlgThreadProc(THREAD *thread, void *param)\r
+{\r
+       UI_MSG_DLG *dlg = (UI_MSG_DLG *)param;\r
+       wchar_t tmp[MAX_SIZE];\r
+       char url[MAX_SIZE];\r
+       // 引数チェック\r
+       if (thread == NULL || dlg == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       UniFormat(tmp, sizeof(tmp), _UU("CM_MSG_TITLE"),\r
+               dlg->ServerName, dlg->HubName);\r
+\r
+       if (IsURLMsg(dlg->Msg, url, sizeof(url)) == false)\r
+       {\r
+               OnceMsgEx(NULL, tmp, dlg->Msg, true, 167, &dlg->Halt);\r
+       }\r
+       else\r
+       {\r
+               if (MsExecute(url, NULL) == false)\r
+               {\r
+                       OnceMsgEx(NULL, tmp, dlg->Msg, true, 167, &dlg->Halt);\r
+               }\r
+       }\r
+\r
+       Disconnect(dlg->Sock);\r
+}\r
+\r
+// NIC 情報ダイアログスレッドプロシージャ\r
+void Win32CnNicInfoThreadProc(THREAD *thread, void *param)\r
+{\r
+       UI_NICINFO *info = (UI_NICINFO *)param;\r
+       // 引数チェック\r
+       if (thread == NULL || info == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       if (MsIsNt())\r
+       {\r
+               // Windows 9x 系ではダイアログを表示しない\r
+               NicInfo(info);\r
+       }\r
+\r
+       Disconnect(info->Sock);\r
+}\r
+\r
+// NIC 情報ダイアログ\r
+void Win32CnNicInfo(SOCK *s, PACK *p)\r
+{\r
+       UI_NICINFO info;\r
+       THREAD *t;\r
+       Zero(&info, sizeof(info));\r
+       // 引数チェック\r
+       if (s == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       PackGetStr(p, "NicName", info.NicName, sizeof(info.NicName));\r
+       PackGetUniStr(p, "AccountName", info.AccountName, sizeof(info.AccountName));\r
+\r
+       info.Sock = s;\r
+\r
+       t = NewThread(Win32CnNicInfoThreadProc, &info);\r
+\r
+       FreePack(RecvPack(s));\r
+\r
+       info.Halt = true;\r
+\r
+       WaitThread(t, INFINITE);\r
+       ReleaseThread(t);\r
+}\r
+\r
+// メッセージ表示ダイアログ\r
+void Win32CnMsgDlg(SOCK *s, PACK *p)\r
+{\r
+       UI_MSG_DLG dlg;\r
+       THREAD *t;\r
+       UINT utf_size;\r
+       char *utf;\r
+       wchar_t *msg;\r
+       Zero(&dlg, sizeof(dlg));\r
+       // 引数チェック\r
+       if (s == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       PackGetStr(p, "ServerName", dlg.ServerName, sizeof(dlg.ServerName));\r
+       PackGetStr(p, "HubName", dlg.HubName, sizeof(dlg.HubName));\r
+\r
+       utf_size = PackGetDataSize(p, "Msg");\r
+       utf = ZeroMalloc(utf_size + 8);\r
+\r
+       PackGetData(p, "Msg", utf);\r
+\r
+       msg = CopyUtfToUni(utf);\r
+       Free(utf);\r
+\r
+       dlg.Sock = s;\r
+       dlg.Msg = msg;\r
+\r
+       t = NewThread(Win32CnMsgDlgThreadProc, &dlg);\r
+\r
+       FreePack(RecvPack(s));\r
+\r
+       dlg.Halt = true;\r
+\r
+       WaitThread(t, INFINITE);\r
+       ReleaseThread(t);\r
+\r
+       Free(msg);\r
+}\r
+\r
+// パスワード入力ダイアログ用スレッド\r
+void Win32CnPasswordDlgThreadProc(THREAD *thread, void *param)\r
+{\r
+       UI_PASSWORD_DLG *dlg;\r
+       // 引数チェック\r
+       if (thread == NULL || param == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       dlg = (UI_PASSWORD_DLG *)param;\r
+\r
+       if (PasswordDlg(NULL, dlg))\r
+       {\r
+               PACK *p = NewPack();\r
+\r
+               PackAddBool(p, "ok", true);\r
+               PackAddStr(p, "Username", dlg->Username);\r
+               PackAddStr(p, "Password", dlg->Password);\r
+               PackAddInt(p, "Type", dlg->Type);\r
+               PackAddBool(p, "ProxyServer", dlg->ProxyServer);\r
+               PackAddBool(p, "NoSavePassword", dlg->NoSavePassword);\r
+\r
+               SendPack(dlg->Sock, p);\r
+               FreePack(p);\r
+\r
+               FreePack(RecvPack(dlg->Sock));\r
+       }\r
+\r
+       Disconnect(dlg->Sock);\r
+}\r
+\r
+// パスワード入力ダイアログ\r
+void Win32CnPasswordDlg(SOCK *s, PACK *p)\r
+{\r
+       UI_PASSWORD_DLG dlg;\r
+       THREAD *t = NULL;\r
+       Zero(&dlg, sizeof(dlg));\r
+       // 引数チェック\r
+       if (s == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       dlg.Type = PackGetInt(p, "Type");\r
+       PackGetStr(p, "Username", dlg.Username, sizeof(dlg.Username));\r
+       PackGetStr(p, "Password", dlg.Password, sizeof(dlg.Password));\r
+       PackGetStr(p, "ServerName", dlg.ServerName, sizeof(dlg.ServerName));\r
+       dlg.RetryIntervalSec = PackGetInt(p, "RetryIntervalSec");\r
+       dlg.ProxyServer = PackGetBool(p, "ProxyServer");\r
+       dlg.AdminMode = PackGetBool(p, "AdminMode");\r
+       dlg.ShowNoSavePassword = PackGetBool(p, "ShowNoSavePassword");\r
+       dlg.NoSavePassword = PackGetBool(p, "NoSavePassword");\r
+       dlg.CancelEvent = NewEvent();\r
+       dlg.Sock = s;\r
+\r
+       t = NewThread(Win32CnPasswordDlgThreadProc, &dlg);\r
+\r
+       FreePack(RecvPack(s));\r
+\r
+       Set(dlg.CancelEvent);\r
+\r
+       WaitThread(t, INFINITE);\r
+       ReleaseEvent(dlg.CancelEvent);\r
+       ReleaseThread(t);\r
+}\r
+\r
+// 接続エラーダイアログ用スレッド\r
+void Win32CnConnectErrorDlgThreadProc(THREAD *thread, void *param)\r
+{\r
+       UI_CONNECTERROR_DLG *dlg;\r
+       // 引数チェック\r
+       if (thread == NULL || param == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       dlg = (UI_CONNECTERROR_DLG *)param;\r
+\r
+       if (ConnectErrorDlg(dlg))\r
+       {\r
+               PACK *p = NewPack();\r
+\r
+               PackAddBool(p, "ok", true);\r
+               PackAddBool(p, "HideWindow", dlg->HideWindow);\r
+\r
+               SendPack(dlg->Sock, p);\r
+               FreePack(p);\r
+\r
+               FreePack(RecvPack(dlg->Sock));\r
+       }\r
+\r
+       Disconnect(dlg->Sock);\r
+}\r
+\r
+// 接続エラーダイアログ (Win32)\r
+void Win32CnConnectErrorDlg(SOCK *s, PACK *p)\r
+{\r
+       UI_CONNECTERROR_DLG dlg;\r
+       THREAD *t;\r
+       Zero(&dlg, sizeof(dlg));\r
+       // 引数チェック\r
+       if (s == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       PackGetUniStr(p, "AccountName", dlg.AccountName, sizeof(dlg.AccountName));\r
+       PackGetStr(p, "ServerName", dlg.ServerName, sizeof(dlg.ServerName));\r
+       dlg.Err = PackGetInt(p, "Err");\r
+       dlg.CurrentRetryCount = PackGetInt(p, "CurrentRetryCount");\r
+       dlg.RetryLimit = PackGetInt(p, "RetryLimit");\r
+       dlg.RetryIntervalSec = PackGetInt(p, "RetryIntervalSec");\r
+       dlg.HideWindow = PackGetBool(p, "HideWindow");\r
+       dlg.CancelEvent = NewEvent();\r
+       dlg.Sock = s;\r
+\r
+       t = NewThread(Win32CnConnectErrorDlgThreadProc, &dlg);\r
+\r
+       FreePack(RecvPack(s));\r
+\r
+       Set(dlg.CancelEvent);\r
+\r
+       WaitThread(t, INFINITE);\r
+       ReleaseEvent(dlg.CancelEvent);\r
+       ReleaseThread(t);\r
+}\r
+\r
+// ステータス表示器 (Win32)\r
+void Win32CnStatusPrinter(SOCK *s, PACK *p)\r
+{\r
+       STATUS_WINDOW *w;\r
+       wchar_t account_name[MAX_ACCOUNT_NAME_LEN + 1];\r
+       // 引数チェック\r
+       if (s == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       PackGetUniStr(p, "account_name", account_name, sizeof(account_name));\r
+\r
+       w = StatusPrinterWindowStart(s, account_name);\r
+\r
+       while (true)\r
+       {\r
+               PACK *p = RecvPack(s);\r
+\r
+               if (p == NULL)\r
+               {\r
+                       // 切断されたのでダイアログを終了する\r
+                       break;\r
+               }\r
+               else\r
+               {\r
+                       wchar_t tmp[MAX_SIZE];\r
+\r
+                       // 文字列を書き換える\r
+                       PackGetUniStr(p, "string", tmp, sizeof(tmp));\r
+\r
+                       StatusPrinterWindowPrint(w, tmp);\r
+\r
+                       FreePack(p);\r
+               }\r
+       }\r
+\r
+       StatusPrinterWindowStop(w);\r
+}\r
+\r
+// ドライバインストーラの起動 (Windows Vista 用)\r
+void Win32CnExecDriverInstaller(SOCK *s, PACK *p)\r
+{\r
+       char arg[MAX_SIZE];\r
+       bool ret;\r
+       void *helper = NULL;\r
+       // 引数チェック\r
+       if (s == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       if (PackGetStr(p, "arg", arg, sizeof(arg)) == false)\r
+       {\r
+               return;\r
+       }\r
+\r
+       if (MsIsVista())\r
+       {\r
+               helper = CmStartUacHelper();\r
+       }\r
+\r
+       ret = MsExecDriverInstaller(arg);\r
+\r
+       CmStopUacHelper(helper);\r
+\r
+       p = NewPack();\r
+       PackAddBool(p, "ret", ret);\r
+       SendPack(s, p);\r
+\r
+       FreePack(p);\r
+}\r
+\r
+#endif // OS_WIN32\r
+\r
+// ドライバインストーラの起動\r
+void CnExecDriverInstaller(SOCK *s, PACK *p)\r
+{\r
+       // 引数チェック\r
+       if (s == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+#ifdef OS_WIN32\r
+       Win32CnExecDriverInstaller(s, p);\r
+#endif // OS_WIN32\r
+}\r
+\r
+// 証明書確認ダイアログ\r
+void CnCheckCert(SOCK *s, PACK *p)\r
+{\r
+       // 引数チェック\r
+       if (s == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+#ifdef OS_WIN32\r
+       Win32CnCheckCert(s, p);\r
+#endif // OS_WIN32\r
+}\r
+\r
+// NIC 情報ダイアログ\r
+void CnNicInfo(SOCK *s, PACK *p)\r
+{\r
+       // 引数チェック\r
+       if (s == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+#ifdef OS_WIN32\r
+       Win32CnNicInfo(s, p);\r
+#endif // OS_WIN32\r
+}\r
+\r
+// メッセージ表示ダイアログ\r
+void CnMsgDlg(SOCK *s, PACK *p)\r
+{\r
+       // 引数チェック\r
+       if (s == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+#ifdef OS_WIN32\r
+       Win32CnMsgDlg(s, p);\r
+#endif // OS_WIN32\r
+}\r
+\r
+// パスワード入力ダイアログ\r
+void CnPasswordDlg(SOCK *s, PACK *p)\r
+{\r
+       // 引数チェック\r
+       if (s == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+#ifdef OS_WIN32\r
+       Win32CnPasswordDlg(s, p);\r
+#endif // OS_WIN32\r
+}\r
+\r
+// 接続エラーダイアログ\r
+void CnConnectErrorDlg(SOCK *s, PACK *p)\r
+{\r
+       // 引数チェック\r
+       if (s == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+#ifdef OS_WIN32\r
+       Win32CnConnectErrorDlg(s, p);\r
+#endif // OS_WIN32\r
+}\r
+\r
+// ステータス表示器\r
+void CnStatusPrinter(SOCK *s, PACK *p)\r
+{\r
+       // 引数チェック\r
+       if (s == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+#ifdef OS_WIN32\r
+       Win32CnStatusPrinter(s, p);\r
+#endif // OS_WIN32\r
+}\r
+\r
+// クライアント通知サービスリスナースレッド\r
+// このあたりは急いで実装したのでコードがあまり美しくない。\r
+void CnListenerProc(THREAD *thread, void *param)\r
+{\r
+       TCP_ACCEPTED_PARAM *data = (TCP_ACCEPTED_PARAM *)param;\r
+       SOCK *s;\r
+       PACK *p;\r
+       // 引数チェック\r
+       if (data == NULL || thread == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       s = data->s;\r
+       AddRef(s->ref);\r
+       NoticeThreadInit(thread);\r
+\r
+       if (s->LocalIP.addr[0] == 127)\r
+       {\r
+               p = RecvPack(s);\r
+\r
+               if (p != NULL)\r
+               {\r
+                       char function[MAX_SIZE];\r
+\r
+                       if (PackGetStr(p, "function", function, sizeof(function)))\r
+                       {\r
+                               if (StrCmpi(function, "status_printer") == 0)\r
+                               {\r
+                                       CnStatusPrinter(s, p);\r
+                               }\r
+                               else if (StrCmpi(function, "connecterror_dialog") == 0)\r
+                               {\r
+                                       CnConnectErrorDlg(s, p);\r
+                               }\r
+                               else if (StrCmpi(function, "msg_dialog") == 0)\r
+                               {\r
+                                       CnMsgDlg(s, p);\r
+                               }\r
+                               else if (StrCmpi(function, "nicinfo") == 0)\r
+                               {\r
+                                       CnNicInfo(s, p);\r
+                               }\r
+                               else if (StrCmpi(function, "password_dialog") == 0)\r
+                               {\r
+                                       CnPasswordDlg(s, p);\r
+                               }\r
+                               else if (StrCmpi(function, "secure_sign") == 0)\r
+                               {\r
+                                       CnSecureSign(s, p);\r
+                               }\r
+                               else if (StrCmpi(function, "check_cert") == 0)\r
+                               {\r
+                                       CnCheckCert(s, p);\r
+                               }\r
+                               else if (StrCmpi(function, "exit") == 0)\r
+                               {\r
+#ifdef OS_WIN32\r
+                                       MsTerminateProcess();\r
+#else  // OS_WIN32\r
+                                       _exit(0);\r
+#endif // OS_WIN32\r
+                               }\r
+                               else if (StrCmpi(function, "get_session_id") == 0)\r
+                               {\r
+                                       PACK *p = NewPack();\r
+#ifdef OS_WIN32\r
+                                       PackAddInt(p, "session_id", MsGetCurrentTerminalSessionId());\r
+#endif // OS_WIN32\r
+                                       SendPack(s, p);\r
+                                       FreePack(p);\r
+                               }\r
+                               else if (StrCmpi(function, "exec_driver_installer") == 0)\r
+                               {\r
+                                       CnExecDriverInstaller(s, p);\r
+                               }\r
+                               else if (StrCmpi(function, "release_socket") == 0)\r
+                               {\r
+                                       // リスナーを停止する\r
+                                       CnReleaseSocket(s, p);\r
+                               }\r
+                       }\r
+\r
+                       FreePack(p);\r
+               }\r
+       }\r
+\r
+       Disconnect(s);\r
+       ReleaseSock(s);\r
+}\r
+\r
+// Secure Sign を行う\r
+void CnSecureSign(SOCK *s, PACK *p)\r
+{\r
+       SECURE_SIGN sign;\r
+       bool ret = false;\r
+       // 引数チェック\r
+       if (s == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Zero(&sign, sizeof(sign));\r
+       InRpcSecureSign(&sign, p);\r
+\r
+#ifdef OS_WIN32\r
+       // Win32: ダイアログを表示\r
+       ret = Win32CiSecureSign(&sign);\r
+#else  // OS_WIN32\r
+       // UNIX: 未実装\r
+       ret = false;\r
+#endif // OS_WIN32\r
+\r
+       p = NewPack();\r
+\r
+       OutRpcSecureSign(p, &sign);\r
+       FreeRpcSecureSign(&sign);\r
+\r
+       PackAddBool(p, "ret", ret);\r
+\r
+       SendPack(s, p);\r
+       FreePack(p);\r
+}\r
+\r
+// リスナーを停止する\r
+void CnReleaseSocket(SOCK *s, PACK *p)\r
+{\r
+       UINT pid = 0;\r
+       UINT current_pid = 0;\r
+       // 引数チェック\r
+       if (s == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       pid = PackGetInt(p, "pid");\r
+\r
+#ifdef OS_WIN32\r
+       current_pid = MsGetProcessId();\r
+#endif // OS_WIN32\r
+\r
+       if (current_pid == pid)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Lock(cn_listener_lock);\r
+       {\r
+               if (cn_listener != NULL)\r
+               {\r
+                       if (cn_listener->Halt == false)\r
+                       {\r
+                               StopListener(cn_listener);\r
+\r
+                               cn_next_allow = Tick64() + (6 * 1000);\r
+                       }\r
+               }\r
+       }\r
+       Unlock(cn_listener_lock);\r
+}\r
+\r
+// クライアント通知サービスの開始\r
+void CnStart()\r
+{\r
+       CEDAR *cedar;\r
+       LISTENER *o;\r
+       UINT last_cursor_hash = 0;\r
+       bool last_session_active = false;\r
+\r
+       cn_next_allow = 0;\r
+       cn_listener_lock = NewLock();\r
+\r
+#ifdef OS_WIN32\r
+       MsSetShutdownParameters(0xff, 0x00000001);\r
+       InitWinUi(_UU("CN_TITLE"), _SS("DEFAULT_FONT"), _II("DEFAULT_FONT_SIZE"));\r
+#endif // OS_WIN32\r
+\r
+       cedar = NewCedar(NULL, NULL);\r
+\r
+       if (CnCheckAlreadyExists(true))\r
+       {\r
+               // すでに起動している\r
+               ReleaseCedar(cedar);\r
+#ifdef OS_WIN32\r
+               FreeWinUi();\r
+#endif // OS_WIN32\r
+               return;\r
+       }\r
+\r
+#ifdef OS_WIN32\r
+       MsRegWriteInt(REG_CURRENT_USER, CM_REG_KEY,\r
+               "NotifyServerProcessId", MsGetProcessId());\r
+#endif // OS_WIN32\r
+\r
+BEGIN_LISTENER:\r
+       Lock(cn_listener_lock);\r
+       cn_listener = o = NewListenerEx(cedar, LISTENER_TCP, CLIENT_NOTIFY_PORT, CnListenerProc, NULL);\r
+       Unlock(cn_listener_lock);\r
+\r
+       while (true)\r
+       {\r
+               UINT current_cursor_hash = 0;\r
+               bool cursor_changed = false;\r
+\r
+#ifdef OS_WIN32\r
+               // 現在のカーソル位置を取得\r
+               current_cursor_hash = MsGetCursorPosHash();\r
+#endif // OS_WIN32\r
+\r
+               if (last_cursor_hash != current_cursor_hash)\r
+               {\r
+                       // カーソル位置をチェック\r
+                       cursor_changed = true;\r
+                       last_cursor_hash = current_cursor_hash;\r
+               }\r
+\r
+               Lock(cn_listener_lock);\r
+\r
+               // リスナーが開始した後一定間隔で状態をチェックする\r
+               if (cn_listener->Status == LISTENER_STATUS_TRYING || cn_listener->Halt)\r
+               {\r
+                       bool session_active = false;\r
+#ifdef OS_WIN32\r
+                       session_active = MsIsCurrentTerminalSessionActive();\r
+                       if (cursor_changed)\r
+                       {\r
+                               // カーソル位置が変化してもターミナルセッションがアクティブでない\r
+                               // 場合は変化していないものと見なす\r
+                               if (session_active == false)\r
+                               {\r
+                                       cursor_changed = false;\r
+                               }\r
+                       }\r
+                       if (last_session_active != session_active)\r
+                       {\r
+                               // カーソルが変化していなくてもターミナルセッション\r
+                               // 前回と比較してアクティブになった場合はカーソルが変化した\r
+                               // ものとみなす\r
+                               last_session_active = session_active;\r
+\r
+                               if (session_active)\r
+                               {\r
+                                       cursor_changed = true;\r
+                               }\r
+                       }\r
+#endif // OS_WIN32\r
+\r
+                       // ポートが開けない場合\r
+                       if (cn_next_allow <= Tick64())\r
+                       {\r
+                               if (cursor_changed || cn_listener->Halt)\r
+                               {\r
+                                       if (cursor_changed)\r
+                                       {\r
+                                               // マウスカーソルが移動しているので自分がポートを開く権利を持っている\r
+                                               // と判断できる。\r
+                                               // そこで、他のプロセスが持っているポートを強制的に奪う。\r
+                                               CncReleaseSocket();\r
+                                       }\r
+\r
+                                       if (cn_listener->Halt)\r
+                                       {\r
+                                               ReleaseListener(cn_listener);\r
+                                               cn_listener = NULL;\r
+\r
+                                               Unlock(cn_listener_lock);\r
+                                               goto BEGIN_LISTENER;\r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+\r
+               Unlock(cn_listener_lock);\r
+\r
+               SleepThread(1000);\r
+       }\r
+}\r
+\r
+// バッファからアカウント情報を読み込む\r
+RPC_CLIENT_CREATE_ACCOUNT *CiCfgToAccount(BUF *b)\r
+{\r
+       RPC_CLIENT_CREATE_ACCOUNT *t;\r
+       FOLDER *f;\r
+       ACCOUNT *a;\r
+       // 引数チェック\r
+       if (b == NULL)\r
+       {\r
+               return NULL;\r
+       }\r
+\r
+       f = CfgBufTextToFolder(b);\r
+       if (f == NULL)\r
+       {\r
+               return NULL;\r
+       }\r
+\r
+       a = CiLoadClientAccount(f);\r
+\r
+       CfgDeleteFolder(f);\r
+\r
+       if (a == NULL)\r
+       {\r
+               return NULL;\r
+       }\r
+\r
+       DeleteLock(a->lock);\r
+\r
+       t = ZeroMalloc(sizeof(RPC_CLIENT_CREATE_ACCOUNT));\r
+       t->ClientOption = a->ClientOption;\r
+       t->ClientAuth = a->ClientAuth;\r
+       t->StartupAccount = a->StartupAccount;\r
+       t->CheckServerCert = a->CheckServerCert;\r
+       t->ServerCert = a->ServerCert;\r
+       Free(a);\r
+\r
+       return t;\r
+}\r
+\r
+// アカウント情報をバッファに書き出す\r
+BUF *CiAccountToCfg(RPC_CLIENT_CREATE_ACCOUNT *t)\r
+{\r
+       BUF *b;\r
+       FOLDER *root;\r
+       ACCOUNT a;\r
+       // 引数チェック\r
+       if (t == NULL)\r
+       {\r
+               return NULL;\r
+       }\r
+\r
+       root = CfgCreateFolder(NULL, TAG_ROOT);\r
+       Zero(&a, sizeof(a));\r
+       a.ClientOption = t->ClientOption;\r
+       a.ClientAuth = t->ClientAuth;\r
+       a.CheckServerCert = t->CheckServerCert;\r
+       a.ServerCert = t->ServerCert;\r
+       a.StartupAccount = t->StartupAccount;\r
+\r
+       CiWriteAccountData(root, &a);\r
+\r
+       b = CfgFolderToBufEx(root, true, true);\r
+       CfgDeleteFolder(root);\r
+\r
+       return b;\r
+}\r
+\r
+// RPC ディスパッチルーチン\r
+PACK *CiRpcDispatch(RPC *rpc, char *name, PACK *p)\r
+{\r
+       CLIENT *c = rpc->Param;\r
+       PACK *ret;\r
+       // 引数チェック\r
+       if (rpc == NULL || name == NULL || p == NULL)\r
+       {\r
+               return NULL;\r
+       }\r
+\r
+       ret = NewPack();\r
+\r
+       if (StrCmpi(name, "GetClientVersion") == 0)\r
+       {\r
+               RPC_CLIENT_VERSION a;\r
+               if (CtGetClientVersion(c, &a) == false)\r
+               {\r
+                       RpcError(ret, c->Err);\r
+               }\r
+               else\r
+               {\r
+                       OutRpcClientVersion(ret, &a);\r
+               }\r
+       }\r
+       else if (StrCmpi(name, "GetCmSetting") == 0)\r
+       {\r
+               CM_SETTING a;\r
+               if (CtGetCmSetting(c, &a) == false)\r
+               {\r
+                       RpcError(ret, c->Err);\r
+               }\r
+               else\r
+               {\r
+                       OutRpcCmSetting(ret, &a);\r
+               }\r
+       }\r
+       else if (StrCmpi(name, "SetCmSetting") == 0)\r
+       {\r
+               CM_SETTING a;\r
+               Zero(&a, sizeof(a));\r
+               InRpcCmSetting(&a, p);\r
+               if (CtSetCmSetting(c, &a) == false)\r
+               {\r
+                       RpcError(ret, c->Err);\r
+               }\r
+       }\r
+       else if (StrCmpi(name, "SetPassword") == 0)\r
+       {\r
+               RPC_CLIENT_PASSWORD a;\r
+               InRpcClientPassword(&a, p);\r
+               if (CtSetPassword(c, &a) == false)\r
+               {\r
+                       RpcError(ret, c->Err);\r
+               }\r
+       }\r
+       else if (StrCmpi(name, "GetPasswordSetting") == 0)\r
+       {\r
+               RPC_CLIENT_PASSWORD_SETTING a;\r
+               if (CtGetPasswordSetting(c, &a) == false)\r
+               {\r
+                       RpcError(ret, c->Err);\r
+               }\r
+               else\r
+               {\r
+                       OutRpcClientPasswordSetting(ret, &a);\r
+               }\r
+       }\r
+       else if (StrCmpi(name, "EnumCa") == 0)\r
+       {\r
+               RPC_CLIENT_ENUM_CA a;\r
+               if (CtEnumCa(c, &a) == false)\r
+               {\r
+                       RpcError(ret, c->Err);\r
+               }\r
+               else\r
+               {\r
+                       OutRpcClientEnumCa(ret, &a);\r
+                       CiFreeClientEnumCa(&a);\r
+               }\r
+       }\r
+       else if (StrCmpi(name, "AddCa") == 0)\r
+       {\r
+               RPC_CERT a;\r
+               InRpcCert(&a, p);\r
+               if (CtAddCa(c, &a) == false)\r
+               {\r
+                       RpcError(ret, c->Err);\r
+               }\r
+               FreeX(a.x);\r
+       }\r
+       else if (StrCmpi(name, "DeleteCa") == 0)\r
+       {\r
+               RPC_CLIENT_DELETE_CA a;\r
+               InRpcClientDeleteCa(&a, p);\r
+               if (CtDeleteCa(c, &a) == false)\r
+               {\r
+                       RpcError(ret, c->Err);\r
+               }\r
+       }\r
+       else if (StrCmpi(name, "GetCa") == 0)\r
+       {\r
+               RPC_GET_CA a;\r
+               InRpcGetCa(&a, p);\r
+               if (CtGetCa(c, &a) == false)\r
+               {\r
+                       RpcError(ret, c->Err);\r
+               }\r
+               else\r
+               {\r
+                       OutRpcGetCa(ret, &a);\r
+               }\r
+               CiFreeGetCa(&a);\r
+       }\r
+       else if (StrCmpi(name, "EnumSecure") == 0)\r
+       {\r
+               RPC_CLIENT_ENUM_SECURE a;\r
+               if (CtEnumSecure(c, &a) == false)\r
+               {\r
+                       RpcError(ret, c->Err);\r
+               }\r
+               else\r
+               {\r
+                       OutRpcClientEnumSecure(ret, &a);\r
+                       CiFreeClientEnumSecure(&a);\r
+               }\r
+       }\r
+       else if (StrCmpi(name, "UseSecure") == 0)\r
+       {\r
+               RPC_USE_SECURE a;\r
+               InRpcUseSecure(&a, p);\r
+               if (CtUseSecure(c, &a) == false)\r
+               {\r
+                       RpcError(ret, c->Err);\r
+               }\r
+       }\r
+       else if (StrCmpi(name, "GetUseSecure") == 0)\r
+       {\r
+               RPC_USE_SECURE a;\r
+               Zero(&a, sizeof(a));\r
+               if (CtGetUseSecure(c, &a) == false)\r
+               {\r
+                       RpcError(ret, c->Err);\r
+               }\r
+               else\r
+               {\r
+                       OutRpcUseSecure(ret, &a);\r
+               }\r
+       }\r
+       else if (StrCmpi(name, "EnumObjectInSecure") == 0)\r
+       {\r
+               RPC_ENUM_OBJECT_IN_SECURE a;\r
+               if (CtEnumObjectInSecure(c, &a) == false)\r
+               {\r
+                       RpcError(ret, c->Err);\r
+               }\r
+               else\r
+               {\r
+                       OutRpcEnumObjectInSecure(ret, &a);\r
+                       CiFreeEnumObjectInSecure(&a);\r
+               }\r
+       }\r
+       else if (StrCmpi(name, "CreateVLan") == 0)\r
+       {\r
+               RPC_CLIENT_CREATE_VLAN a;\r
+               InRpcCreateVLan(&a, p);\r
+               if (CtCreateVLan(c, &a) == false)\r
+               {\r
+                       RpcError(ret, c->Err);\r
+               }\r
+       }\r
+       else if (StrCmpi(name, "UpgradeVLan") == 0)\r
+       {\r
+               RPC_CLIENT_CREATE_VLAN a;\r
+               InRpcCreateVLan(&a, p);\r
+               if (CtUpgradeVLan(c, &a) == false)\r
+               {\r
+                       RpcError(ret, c->Err);\r
+               }\r
+       }\r
+       else if (StrCmpi(name, "GetVLan") == 0)\r
+       {\r
+               RPC_CLIENT_GET_VLAN a;\r
+               InRpcClientGetVLan(&a, p);\r
+               if (CtGetVLan(c, &a) == false)\r
+               {\r
+                       RpcError(ret, c->Err);\r
+               }\r
+               else\r
+               {\r
+                       OutRpcClientGetVLan(ret, &a);\r
+               }\r
+       }\r
+       else if (StrCmpi(name, "SetVLan") == 0)\r
+       {\r
+               RPC_CLIENT_SET_VLAN a;\r
+               InRpcClientSetVLan(&a, p);\r
+               if (CtSetVLan(c, &a) == false)\r
+               {\r
+                       RpcError(ret, c->Err);\r
+               }\r
+       }\r
+       else if (StrCmpi(name, "EnumVLan") == 0)\r
+       {\r
+               RPC_CLIENT_ENUM_VLAN a;\r
+               if (CtEnumVLan(c, &a) == false)\r
+               {\r
+                       RpcError(ret, c->Err);\r
+               }\r
+               else\r
+               {\r
+                       OutRpcClientEnumVLan(ret, &a);\r
+                       CiFreeClientEnumVLan(&a);\r
+               }\r
+       }\r
+       else if (StrCmpi(name, "DeleteVLan") == 0)\r
+       {\r
+               RPC_CLIENT_CREATE_VLAN a;\r
+               InRpcCreateVLan(&a, p);\r
+               if (CtDeleteVLan(c, &a) == false)\r
+               {\r
+                       RpcError(ret, c->Err);\r
+               }\r
+       }\r
+       else if (StrCmpi(name, "EnableVLan") == 0)\r
+       {\r
+               RPC_CLIENT_CREATE_VLAN a;\r
+               InRpcCreateVLan(&a, p);\r
+               if (CtEnableVLan(c, &a) == false)\r
+               {\r
+                       RpcError(ret, c->Err);\r
+               }\r
+       }\r
+       else if (StrCmpi(name, "DisableVLan") == 0)\r
+       {\r
+               RPC_CLIENT_CREATE_VLAN a;\r
+               InRpcCreateVLan(&a, p);\r
+               if (CtDisableVLan(c, &a) == false)\r
+               {\r
+                       RpcError(ret, c->Err);\r
+               }\r
+       }\r
+       else if (StrCmpi(name, "CreateAccount") == 0)\r
+       {\r
+               RPC_CLIENT_CREATE_ACCOUNT a;\r
+               InRpcClientCreateAccount(&a, p);\r
+               if (CtCreateAccount(c, &a) == false)\r
+               {\r
+                       RpcError(ret, c->Err);\r
+               }\r
+               CiFreeClientCreateAccount(&a);\r
+       }\r
+       else if (StrCmpi(name, "EnumAccount") == 0)\r
+       {\r
+               RPC_CLIENT_ENUM_ACCOUNT a;\r
+               if (CtEnumAccount(c, &a) == false)\r
+               {\r
+                       RpcError(ret, c->Err);\r
+               }\r
+               else\r
+               {\r
+                       OutRpcClientEnumAccount(ret, &a);\r
+                       CiFreeClientEnumAccount(&a);\r
+               }\r
+       }\r
+       else if (StrCmpi(name, "DeleteAccount") == 0)\r
+       {\r
+               RPC_CLIENT_DELETE_ACCOUNT a;\r
+               InRpcClientDeleteAccount(&a, p);\r
+               if (CtDeleteAccount(c, &a) == false)\r
+               {\r
+                       RpcError(ret, c->Err);\r
+               }\r
+       }\r
+       else if (StrCmpi(name, "SetStartupAccount") == 0)\r
+       {\r
+               RPC_CLIENT_DELETE_ACCOUNT a;\r
+               InRpcClientDeleteAccount(&a, p);\r
+               if (CtSetStartupAccount(c, &a) == false)\r
+               {\r
+                       RpcError(ret, c->Err);\r
+               }\r
+       }\r
+       else if (StrCmpi(name, "RemoveStartupAccount") == 0)\r
+       {\r
+               RPC_CLIENT_DELETE_ACCOUNT a;\r
+               InRpcClientDeleteAccount(&a, p);\r
+               if (CtRemoveStartupAccount(c, &a) == false)\r
+               {\r
+                       RpcError(ret, c->Err);\r
+               }\r
+       }\r
+       else if (StrCmpi(name, "GetIssuer") == 0)\r
+       {\r
+               RPC_GET_ISSUER a;\r
+               InRpcGetIssuer(&a, p);\r
+               if (CtGetIssuer(c, &a))\r
+               {\r
+                       OutRpcGetIssuer(ret, &a);\r
+               }\r
+               else\r
+               {\r
+                       RpcError(ret, c->Err);\r
+               }\r
+               CiFreeGetIssuer(&a);\r
+       }\r
+       else if (StrCmpi(name, "SetAccount") == 0)\r
+       {\r
+               RPC_CLIENT_CREATE_ACCOUNT a;\r
+               InRpcClientCreateAccount(&a, p);\r
+               if (CtSetAccount(c, &a) == false)\r
+               {\r
+                       RpcError(ret, c->Err);\r
+               }\r
+               CiFreeClientCreateAccount(&a);\r
+       }\r
+       else if (StrCmpi(name, "GetAccount") == 0)\r
+       {\r
+               RPC_CLIENT_GET_ACCOUNT a;\r
+               InRpcClientGetAccount(&a, p);\r
+               if (CtGetAccount(c, &a) == false)\r
+               {\r
+                       RpcError(ret, c->Err);\r
+               }\r
+               else\r
+               {\r
+                       OutRpcClientGetAccount(ret, &a);\r
+               }\r
+               CiFreeClientGetAccount(&a);\r
+       }\r
+       else if (StrCmpi(name, "RenameAccount") == 0)\r
+       {\r
+               RPC_RENAME_ACCOUNT a;\r
+               InRpcRenameAccount(&a, p);\r
+               if (CtRenameAccount(c, &a) == false)\r
+               {\r
+                       RpcError(ret, c->Err);\r
+               }\r
+       }\r
+       else if (StrCmpi(name, "SetClientConfig") == 0)\r
+       {\r
+               CLIENT_CONFIG a;\r
+               InRpcClientConfig(&a, p);\r
+               if (CtSetClientConfig(c, &a) == false)\r
+               {\r
+                       RpcError(ret, c->Err);\r
+               }\r
+       }\r
+       else if (StrCmpi(name, "GetClientConfig") == 0)\r
+       {\r
+               CLIENT_CONFIG a;\r
+               if (CtGetClientConfig(c, &a) == false)\r
+               {\r
+                       RpcError(ret, c->Err);\r
+               }\r
+               else\r
+               {\r
+                       OutRpcClientConfig(ret, &a);\r
+               }\r
+       }\r
+       else if (StrCmpi(name, "Connect") == 0)\r
+       {\r
+               RPC_CLIENT_CONNECT a;\r
+               InRpcClientConnect(&a, p);\r
+               if (CtConnect(c, &a) == false)\r
+               {\r
+                       RpcError(ret, c->Err);\r
+               }\r
+       }\r
+       else if (StrCmpi(name, "Disconnect") == 0)\r
+       {\r
+               RPC_CLIENT_CONNECT a;\r
+               InRpcClientConnect(&a, p);\r
+               if (CtDisconnect(c, &a) == false)\r
+               {\r
+                       RpcError(ret, c->Err);\r
+               }\r
+       }\r
+       else if (StrCmpi(name, "GetAccountStatus") == 0)\r
+       {\r
+               RPC_CLIENT_GET_CONNECTION_STATUS a;\r
+               InRpcClientGetConnectionStatus(&a, p);\r
+               if (CtGetAccountStatus(c, &a) == false)\r
+               {\r
+                       RpcError(ret, c->Err);\r
+               }\r
+               else\r
+               {\r
+                       OutRpcClientGetConnectionStatus(ret, &a);\r
+               }\r
+               CiFreeClientGetConnectionStatus(&a);\r
+       }\r
+       else\r
+       {\r
+               FreePack(ret);\r
+               ret = NULL;\r
+       }\r
+\r
+       return ret;\r
+}\r
+\r
+// CM_SETTING の設定\r
+UINT CcSetCmSetting(REMOTE_CLIENT *r, CM_SETTING *a)\r
+{\r
+       PACK *ret, *p;\r
+       UINT err;\r
+       // 引数チェック\r
+       if (r == NULL || a == NULL)\r
+       {\r
+               return ERR_INTERNAL_ERROR;\r
+       }\r
+\r
+       p = NewPack();\r
+       OutRpcCmSetting(p, a);\r
+\r
+       ret = RpcCall(r->Rpc, "SetCmSetting", p);\r
+\r
+       if (RpcIsOk(ret))\r
+       {\r
+               FreePack(ret);\r
+               return 0;\r
+       }\r
+       else\r
+       {\r
+               err = RpcGetError(ret);\r
+               FreePack(ret);\r
+               return err;\r
+       }\r
+}\r
+\r
+// CM_SETTING の取得\r
+UINT CcGetCmSetting(REMOTE_CLIENT *r, CM_SETTING *a)\r
+{\r
+       PACK *ret;\r
+       // 引数チェック\r
+       if (r == NULL || a == NULL)\r
+       {\r
+               return ERR_INTERNAL_ERROR;\r
+       }\r
+\r
+       ret = RpcCall(r->Rpc, "GetCmSetting", NULL);\r
+\r
+       if (RpcIsOk(ret))\r
+       {\r
+               InRpcCmSetting(a, ret);\r
+               FreePack(ret);\r
+               return 0;\r
+       }\r
+       else\r
+       {\r
+               UINT err = RpcGetError(ret);\r
+               FreePack(ret);\r
+               return err;\r
+       }\r
+}\r
+\r
+// クライアントバージョンの取得\r
+UINT CcGetClientVersion(REMOTE_CLIENT *r, RPC_CLIENT_VERSION *a)\r
+{\r
+       PACK *ret;\r
+       // 引数チェック\r
+       if (r == NULL || a == NULL)\r
+       {\r
+               return ERR_INTERNAL_ERROR;\r
+       }\r
+\r
+       ret = RpcCall(r->Rpc, "GetClientVersion", NULL);\r
+\r
+       if (RpcIsOk(ret))\r
+       {\r
+               InRpcClientVersion(a, ret);\r
+               FreePack(ret);\r
+               return 0;\r
+       }\r
+       else\r
+       {\r
+               UINT err = RpcGetError(ret);\r
+               FreePack(ret);\r
+               return err;\r
+       }\r
+}\r
+\r
+// パスワードの設定\r
+UINT CcSetPassword(REMOTE_CLIENT *r, RPC_CLIENT_PASSWORD *pass)\r
+{\r
+       PACK *ret, *p;\r
+       // 引数チェック\r
+       if (r == NULL || pass == NULL)\r
+       {\r
+               return ERR_INTERNAL_ERROR;\r
+       }\r
+\r
+       p = NewPack();\r
+\r
+       OutRpcClientPassword(p, pass);\r
+\r
+       ret = RpcCall(r->Rpc, "SetPassword", p);\r
+\r
+       if (RpcIsOk(ret))\r
+       {\r
+               FreePack(ret);\r
+               return 0;\r
+       }\r
+       else\r
+       {\r
+               UINT err = RpcGetError(ret);\r
+               FreePack(ret);\r
+               return err;\r
+       }\r
+}\r
+\r
+// パスワード設定の取得\r
+UINT CcGetPasswordSetting(REMOTE_CLIENT *r, RPC_CLIENT_PASSWORD_SETTING *a)\r
+{\r
+       PACK *ret;\r
+       UINT err = 0;\r
+       // 引数チェック\r
+       if (r == NULL || a == NULL)\r
+       {\r
+               return ERR_INTERNAL_ERROR;\r
+       }\r
+\r
+       ret = RpcCall(r->Rpc, "GetPasswordSetting", NULL);\r
+\r
+       if (RpcIsOk(ret))\r
+       {\r
+               InRpcClientPasswordSetting(a, ret);\r
+       }\r
+       else\r
+       {\r
+               err = RpcGetError(ret);\r
+       }\r
+\r
+       FreePack(ret);\r
+       return err;\r
+}\r
+\r
+// CA の列挙\r
+UINT CcEnumCa(REMOTE_CLIENT *r, RPC_CLIENT_ENUM_CA *e)\r
+{\r
+       PACK *ret;\r
+       UINT err = 0;\r
+       // 引数チェック\r
+       if (r == NULL || e == NULL)\r
+       {\r
+               return ERR_INTERNAL_ERROR;\r
+       }\r
+\r
+       ret = RpcCall(r->Rpc, "EnumCa", NULL);\r
+\r
+       if (RpcIsOk(ret))\r
+       {\r
+               InRpcClientEnumCa(e, ret);\r
+       }\r
+       else\r
+       {\r
+               err = RpcGetError(ret);\r
+       }\r
+\r
+       FreePack(ret);\r
+\r
+       return err;\r
+}\r
+\r
+// CA の追加\r
+UINT CcAddCa(REMOTE_CLIENT *r, RPC_CERT *cert)\r
+{\r
+       PACK *p, *ret;\r
+       UINT err = 0;\r
+       // 引数チェック\r
+       if (r == NULL || cert == NULL)\r
+       {\r
+               return ERR_INTERNAL_ERROR;\r
+       }\r
+\r
+       p = NewPack();\r
+       OutRpcCert(p, cert);\r
+\r
+       ret = RpcCall(r->Rpc, "AddCa", p);\r
+\r
+       if (RpcIsOk(ret) == false)\r
+       {\r
+               err = RpcGetError(ret);\r
+       }\r
+\r
+       FreePack(ret);\r
+\r
+       return err;\r
+}\r
+\r
+// CA の削除\r
+UINT CcDeleteCa(REMOTE_CLIENT *r, RPC_CLIENT_DELETE_CA *c)\r
+{\r
+       PACK *p, *ret;\r
+       UINT err = 0;\r
+       // 引数チェック\r
+       if (r == NULL || c == NULL)\r
+       {\r
+               return ERR_INTERNAL_ERROR;\r
+       }\r
+\r
+       p = NewPack();\r
+       OutRpcClientDeleteCa(p, c);\r
+\r
+       ret = RpcCall(r->Rpc, "DeleteCa", p);\r
+\r
+       if (RpcIsOk(ret) == false)\r
+       {\r
+               err = RpcGetError(ret);\r
+       }\r
+\r
+       FreePack(ret);\r
+\r
+       return err;\r
+}\r
+\r
+// 署名者の取得\r
+UINT CcGetIssuer(REMOTE_CLIENT *r, RPC_GET_ISSUER *a)\r
+{\r
+       PACK *p, *ret;\r
+       UINT err = 0;\r
+       // 引数チェック\r
+       if (r == NULL || a == NULL)\r
+       {\r
+               return ERR_INTERNAL_ERROR;\r
+       }\r
+\r
+       p = NewPack();\r
+       OutRpcGetIssuer(p, a);\r
+\r
+       ret = RpcCall(r->Rpc, "GetIssuer", p);\r
+\r
+       if (RpcIsOk(ret))\r
+       {\r
+               if (a->x != NULL)\r
+               {\r
+                       FreeX(a->x);\r
+                       a->x = NULL;\r
+               }\r
+               InRpcGetIssuer(a, ret);\r
+       }\r
+       else\r
+       {\r
+               err = RpcGetError(ret);\r
+       }\r
+\r
+       FreePack(ret);\r
+\r
+       return err;\r
+}\r
+\r
+// CA の取得\r
+UINT CcGetCa(REMOTE_CLIENT *r, RPC_GET_CA *get)\r
+{\r
+       PACK *p, *ret;\r
+       UINT err = 0;\r
+       // 引数チェック\r
+       if (r == NULL || get == NULL)\r
+       {\r
+               return ERR_INTERNAL_ERROR;\r
+       }\r
+\r
+       p = NewPack();\r
+       OutRpcGetCa(p, get);\r
+\r
+       ret = RpcCall(r->Rpc, "GetCa", p);\r
+\r
+       if (RpcIsOk(ret))\r
+       {\r
+               InRpcGetCa(get, ret);\r
+       }\r
+       else\r
+       {\r
+               err = RpcGetError(ret);\r
+       }\r
+\r
+       FreePack(ret);\r
+\r
+       return err;\r
+}\r
+\r
+// セキュアデバイスの列挙\r
+UINT CcEnumSecure(REMOTE_CLIENT *r, RPC_CLIENT_ENUM_SECURE *e)\r
+{\r
+       PACK *ret;\r
+       UINT err = 0;\r
+       // 引数チェック\r
+       if (r == NULL || e == NULL)\r
+       {\r
+               return ERR_INTERNAL_ERROR;\r
+       }\r
+\r
+       ret = RpcCall(r->Rpc, "EnumSecure", NULL);\r
+\r
+       if (RpcIsOk(ret))\r
+       {\r
+               InRpcClientEnumSecure(e, ret);\r
+       }\r
+       else\r
+       {\r
+               err = RpcGetError(ret);\r
+       }\r
+\r
+       FreePack(ret);\r
+\r
+       return err;\r
+}\r
+\r
+// 使用しているセキュアデバイスの取得\r
+UINT CcGetUseSecure(REMOTE_CLIENT *r, RPC_USE_SECURE *sec)\r
+{\r
+       PACK *p, *ret;\r
+       UINT err = 0;\r
+       // 引数チェック\r
+       if (r == NULL || sec == NULL)\r
+       {\r
+               return ERR_INTERNAL_ERROR;\r
+       }\r
+\r
+       p = NewPack();\r
+\r
+       ret = RpcCall(r->Rpc, "GetUseSecure", p);\r
+\r
+       if (RpcIsOk(ret) == false)\r
+       {\r
+               err = RpcGetError(ret);\r
+       }\r
+       else\r
+       {\r
+               InRpcUseSecure(sec, ret);\r
+       }\r
+\r
+       FreePack(ret);\r
+\r
+       return err;\r
+}\r
+\r
+// セキュアデバイスの使用\r
+UINT CcUseSecure(REMOTE_CLIENT *r, RPC_USE_SECURE *sec)\r
+{\r
+       PACK *p, *ret;\r
+       UINT err = 0;\r
+       // 引数チェック\r
+       if (r == NULL || sec == NULL)\r
+       {\r
+               return ERR_INTERNAL_ERROR;\r
+       }\r
+\r
+       p = NewPack();\r
+       OutRpcUseSecure(p, sec);\r
+\r
+       ret = RpcCall(r->Rpc, "UseSecure", p);\r
+\r
+       if (RpcIsOk(ret) == false)\r
+       {\r
+               err = RpcGetError(ret);\r
+       }\r
+\r
+       FreePack(ret);\r
+\r
+       return err;\r
+}\r
+\r
+// セキュアデバイス内のオブジェクトの列挙\r
+UINT CcEnumObjectInSecure(REMOTE_CLIENT *r, RPC_ENUM_OBJECT_IN_SECURE *e)\r
+{\r
+       PACK *ret;\r
+       UINT err = 0;\r
+       // 引数チェック\r
+       if (r == NULL || e == NULL)\r
+       {\r
+               return ERR_INTERNAL_ERROR;\r
+       }\r
+\r
+       ret = RpcCall(r->Rpc, "EnumObjectInSecure", NULL);\r
+\r
+       if (RpcIsOk(ret))\r
+       {\r
+               InRpcEnumObjectInSecure(e, ret);\r
+       }\r
+       else\r
+       {\r
+               err = RpcGetError(ret);\r
+       }\r
+\r
+       FreePack(ret);\r
+\r
+       return err;\r
+}\r
+\r
+// VLAN の作成\r
+UINT CcCreateVLan(REMOTE_CLIENT *r, RPC_CLIENT_CREATE_VLAN *create)\r
+{\r
+       PACK *ret, *p;\r
+       UINT err = 0;\r
+       char *s = NULL;\r
+       // 引数チェック\r
+       if (r == NULL || create == NULL)\r
+       {\r
+               return ERR_INTERNAL_ERROR;\r
+       }\r
+\r
+       p = NewPack();\r
+       OutRpcCreateVLan(p, create);\r
+\r
+#ifdef OS_WIN32\r
+       s = MsNoWarningSoundInit();\r
+#endif // OS_WIN32\r
+\r
+       ret = RpcCall(r->Rpc, "CreateVLan", p);\r
+\r
+#ifdef OS_WIN32\r
+       MsNoWarningSoundFree(s);\r
+#endif // OS_WIN32\r
+\r
+       if (RpcIsOk(ret) == false)\r
+       {\r
+               err = RpcGetError(ret);\r
+       }\r
+\r
+       FreePack(ret);\r
+\r
+       return err;\r
+}\r
+\r
+// VLAN のアップグレード\r
+UINT CcUpgradeVLan(REMOTE_CLIENT *r, RPC_CLIENT_CREATE_VLAN *create)\r
+{\r
+       PACK *ret, *p;\r
+       UINT err = 0;\r
+       char *s = NULL;\r
+       // 引数チェック\r
+       if (r == NULL || create == NULL)\r
+       {\r
+               return ERR_INTERNAL_ERROR;\r
+       }\r
+\r
+       p = NewPack();\r
+       OutRpcCreateVLan(p, create);\r
+\r
+#ifdef OS_WIN32\r
+       s = MsNoWarningSoundInit();\r
+#endif // OS_WIN32\r
+\r
+       ret = RpcCall(r->Rpc, "UpgradeVLan", p);\r
+\r
+#ifdef OS_WIN32\r
+       MsNoWarningSoundFree(s);\r
+#endif // OS_WIN32\r
+\r
+\r
+       if (RpcIsOk(ret) == false)\r
+       {\r
+               err = RpcGetError(ret);\r
+       }\r
+\r
+       FreePack(ret);\r
+\r
+       return err;\r
+}\r
+\r
+// VLAN の取得\r
+UINT CcGetVLan(REMOTE_CLIENT *r, RPC_CLIENT_GET_VLAN *get)\r
+{\r
+       PACK *ret, *p;\r
+       UINT err = 0;\r
+       // 引数チェック\r
+       if (r == NULL || get == NULL)\r
+       {\r
+               return ERR_INTERNAL_ERROR;\r
+       }\r
+\r
+       p = NewPack();\r
+       OutRpcClientGetVLan(p, get);\r
+\r
+       ret = RpcCall(r->Rpc, "GetVLan", p);\r
+\r
+       if (RpcIsOk(ret))\r
+       {\r
+               InRpcClientGetVLan(get, ret);\r
+       }\r
+       else\r
+       {\r
+               err = RpcGetError(ret);\r
+       }\r
+\r
+       FreePack(ret);\r
+\r
+       return err;\r
+}\r
+\r
+// VLAN の設定\r
+UINT CcSetVLan(REMOTE_CLIENT *r, RPC_CLIENT_SET_VLAN *set)\r
+{\r
+       PACK *ret, *p;\r
+       UINT err = 0;\r
+       // 引数チェック\r
+       if (r == NULL || set == NULL)\r
+       {\r
+               return ERR_INTERNAL_ERROR;\r
+       }\r
+\r
+       p = NewPack();\r
+       OutRpcClientSetVLan(p, set);\r
+\r
+       ret = RpcCall(r->Rpc, "SetVLan", p);\r
+\r
+       if (RpcIsOk(ret) == false)\r
+       {\r
+               err = RpcGetError(ret);\r
+       }\r
+\r
+       FreePack(ret);\r
+\r
+       return err;\r
+}\r
+\r
+// VLAN の列挙\r
+UINT CcEnumVLan(REMOTE_CLIENT *r, RPC_CLIENT_ENUM_VLAN *e)\r
+{\r
+       PACK *ret;\r
+       UINT err = 0;\r
+       // 引数チェック\r
+       if (r == NULL || e == NULL)\r
+       {\r
+               return ERR_INTERNAL_ERROR;\r
+       }\r
+\r
+       ret = RpcCall(r->Rpc, "EnumVLan", NULL);\r
+\r
+       if (RpcIsOk(ret))\r
+       {\r
+               InRpcClientEnumVLan(e, ret);\r
+       }\r
+       else\r
+       {\r
+               err = RpcGetError(ret);\r
+       }\r
+\r
+       FreePack(ret);\r
+\r
+       return err;\r
+}\r
+\r
+// VLAN の削除\r
+UINT CcDeleteVLan(REMOTE_CLIENT *r, RPC_CLIENT_CREATE_VLAN *d)\r
+{\r
+       PACK *ret, *p;\r
+       UINT err = 0;\r
+       // 引数チェック\r
+       if (r == NULL || d == NULL)\r
+       {\r
+               return ERR_INTERNAL_ERROR;\r
+       }\r
+\r
+       p = NewPack();\r
+       OutRpcCreateVLan(p, d);\r
+\r
+       ret = RpcCall(r->Rpc, "DeleteVLan", p);\r
+\r
+       if (RpcIsOk(ret) == false)\r
+       {\r
+               err = RpcGetError(ret);\r
+       }\r
+\r
+       FreePack(ret);\r
+\r
+       return err;\r
+}\r
+\r
+// VLAN の有効化\r
+UINT CcEnableVLan(REMOTE_CLIENT *r, RPC_CLIENT_CREATE_VLAN *vlan)\r
+{\r
+       PACK *ret, *p;\r
+       UINT err = 0;\r
+       // 引数チェック\r
+       if (r == NULL || vlan == NULL)\r
+       {\r
+               return ERR_INTERNAL_ERROR;\r
+       }\r
+\r
+       p = NewPack();\r
+       OutRpcCreateVLan(p, vlan);\r
+\r
+       ret = RpcCall(r->Rpc, "EnableVLan", p);\r
+\r
+       if (RpcIsOk(ret) == false)\r
+       {\r
+               err = RpcGetError(ret);\r
+       }\r
+\r
+       FreePack(ret);\r
+\r
+       return err;\r
+}\r
+\r
+// VLAN の無効化\r
+UINT CcDisableVLan(REMOTE_CLIENT *r, RPC_CLIENT_CREATE_VLAN *vlan)\r
+{\r
+       PACK *ret, *p;\r
+       UINT err = 0;\r
+       // 引数チェック\r
+       if (r == NULL || vlan == NULL)\r
+       {\r
+               return ERR_INTERNAL_ERROR;\r
+       }\r
+\r
+       p = NewPack();\r
+       OutRpcCreateVLan(p, vlan);\r
+\r
+       ret = RpcCall(r->Rpc, "DisableVLan", p);\r
+\r
+       if (RpcIsOk(ret) == false)\r
+       {\r
+               err = RpcGetError(ret);\r
+       }\r
+\r
+       FreePack(ret);\r
+\r
+       return err;\r
+}\r
+\r
+// アカウントの作成\r
+UINT CcCreateAccount(REMOTE_CLIENT *r, RPC_CLIENT_CREATE_ACCOUNT *a)\r
+{\r
+       PACK *ret, *p;\r
+       UINT err = 0;\r
+       // 引数チェック\r
+       if (r == NULL || a == NULL)\r
+       {\r
+               return ERR_INTERNAL_ERROR;\r
+       }\r
+\r
+       p = NewPack();\r
+       OutRpcClientCreateAccount(p, a);\r
+\r
+       ret = RpcCall(r->Rpc, "CreateAccount", p);\r
+\r
+       if (RpcIsOk(ret) == false)\r
+       {\r
+               err = RpcGetError(ret);\r
+       }\r
+\r
+       FreePack(ret);\r
+\r
+       return err;\r
+}\r
+\r
+// アカウントの列挙\r
+UINT CcEnumAccount(REMOTE_CLIENT *r, RPC_CLIENT_ENUM_ACCOUNT *e)\r
+{\r
+       PACK *ret;\r
+       UINT err = 0;\r
+       // 引数チェック\r
+       if (r == NULL || e == NULL)\r
+       {\r
+               return ERR_INTERNAL_ERROR;\r
+       }\r
+\r
+       ret = RpcCall(r->Rpc, "EnumAccount", NULL);\r
+\r
+       if (RpcIsOk(ret))\r
+       {\r
+               UINT i;\r
+               InRpcClientEnumAccount(e, ret);\r
+\r
+               for (i = 0;i < e->NumItem;i++)\r
+               {\r
+                       RPC_CLIENT_ENUM_ACCOUNT_ITEM *t = e->Items[i];\r
+\r
+                       if (IsEmptyStr(t->HubName) && t->Port == 0)\r
+                       {\r
+                               UINT err2;\r
+                               RPC_CLIENT_GET_ACCOUNT a;\r
+\r
+                               // 古いバージョンの VPN Client では列挙時に HUB 名とポート番号\r
+                               // を取得できないので、別途取得する。\r
+                               Zero(&a, sizeof(a));\r
+                               UniStrCpy(a.AccountName, sizeof(a.AccountName), t->AccountName);\r
+                               err2 = CcGetAccount(r, &a);\r
+                               if (err2 == ERR_NO_ERROR)\r
+                               {\r
+                                       StrCpy(t->HubName, sizeof(t->HubName), a.ClientOption->HubName);\r
+                                       t->Port = a.ClientOption->Port;\r
+\r
+                                       CiFreeClientGetAccount(&a);\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+       else\r
+       {\r
+               err = RpcGetError(ret);\r
+       }\r
+\r
+       FreePack(ret);\r
+\r
+       return err;\r
+}\r
+\r
+// スタートアップを解除する\r
+UINT CcRemoveStartupAccount(REMOTE_CLIENT *r, RPC_CLIENT_DELETE_ACCOUNT *a)\r
+{\r
+       PACK *ret, *p;\r
+       UINT err = 0;\r
+       // 引数チェック\r
+       if (r == NULL || a == NULL)\r
+       {\r
+               return ERR_INTERNAL_ERROR;\r
+       }\r
+\r
+       p = NewPack();\r
+       OutRpcClientDeleteAccount(p, a);\r
+\r
+       ret = RpcCall(r->Rpc, "RemoveStartupAccount", p);\r
+\r
+       if (RpcIsOk(ret) == false)\r
+       {\r
+               err = RpcGetError(ret);\r
+       }\r
+\r
+       FreePack(ret);\r
+\r
+       return err;\r
+}\r
+\r
+// スタートアップにする\r
+UINT CcSetStartupAccount(REMOTE_CLIENT *r, RPC_CLIENT_DELETE_ACCOUNT *a)\r
+{\r
+       PACK *ret, *p;\r
+       UINT err = 0;\r
+       // 引数チェック\r
+       if (r == NULL || a == NULL)\r
+       {\r
+               return ERR_INTERNAL_ERROR;\r
+       }\r
+\r
+       p = NewPack();\r
+       OutRpcClientDeleteAccount(p, a);\r
+\r
+       ret = RpcCall(r->Rpc, "SetStartupAccount", p);\r
+\r
+       if (RpcIsOk(ret) == false)\r
+       {\r
+               err = RpcGetError(ret);\r
+       }\r
+\r
+       FreePack(ret);\r
+\r
+       return err;\r
+}\r
+\r
+// アカウントの削除\r
+UINT CcDeleteAccount(REMOTE_CLIENT *r, RPC_CLIENT_DELETE_ACCOUNT *a)\r
+{\r
+       PACK *ret, *p;\r
+       UINT err = 0;\r
+       // 引数チェック\r
+       if (r == NULL || a == NULL)\r
+       {\r
+               return ERR_INTERNAL_ERROR;\r
+       }\r
+\r
+       p = NewPack();\r
+       OutRpcClientDeleteAccount(p, a);\r
+\r
+       ret = RpcCall(r->Rpc, "DeleteAccount", p);\r
+\r
+       if (RpcIsOk(ret) == false)\r
+       {\r
+               err = RpcGetError(ret);\r
+       }\r
+\r
+       FreePack(ret);\r
+\r
+       return err;\r
+}\r
+\r
+// アカウントの設定\r
+UINT CcSetAccount(REMOTE_CLIENT *r, RPC_CLIENT_CREATE_ACCOUNT *a)\r
+{\r
+       PACK *ret, *p;\r
+       UINT err = 0;\r
+       // 引数チェック\r
+       if (r == NULL || a == NULL)\r
+       {\r
+               return ERR_INTERNAL_ERROR;\r
+       }\r
+\r
+       p = NewPack();\r
+       OutRpcClientCreateAccount(p, a);\r
+\r
+       ret = RpcCall(r->Rpc, "SetAccount", p);\r
+\r
+       if (RpcIsOk(ret) == false)\r
+       {\r
+               err = RpcGetError(ret);\r
+       }\r
+\r
+       FreePack(ret);\r
+\r
+       return err;\r
+}\r
+\r
+// アカウントの取得\r
+UINT CcGetAccount(REMOTE_CLIENT *r, RPC_CLIENT_GET_ACCOUNT *a)\r
+{\r
+       PACK *ret, *p;\r
+       UINT err = 0;\r
+       // 引数チェック\r
+       if (r == NULL || a == NULL)\r
+       {\r
+               return ERR_INTERNAL_ERROR;\r
+       }\r
+\r
+       p = NewPack();\r
+       OutRpcClientGetAccount(p, a);\r
+\r
+       ret = RpcCall(r->Rpc, "GetAccount", p);\r
+\r
+       if (RpcIsOk(ret))\r
+       {\r
+               InRpcClientGetAccount(a, ret);\r
+       }\r
+       else\r
+       {\r
+               err = RpcGetError(ret);\r
+       }\r
+\r
+       FreePack(ret);\r
+\r
+       return err;\r
+}\r
+\r
+// アカウント名の変更\r
+UINT CcRenameAccount(REMOTE_CLIENT *r, RPC_RENAME_ACCOUNT *rename)\r
+{\r
+       PACK *p, *ret;\r
+       UINT err = 0;\r
+       // 引数チェック\r
+       if (r == NULL || rename == NULL)\r
+       {\r
+               return ERR_INTERNAL_ERROR;\r
+       }\r
+\r
+       p = NewPack();\r
+       OutRpcRenameAccount(p, rename);\r
+\r
+       ret = RpcCall(r->Rpc, "RenameAccount", p);\r
+\r
+       if (RpcIsOk(ret) == false)\r
+       {\r
+               err = RpcGetError(ret);\r
+       }\r
+\r
+       FreePack(ret);\r
+\r
+       return err;\r
+}\r
+\r
+// クライアント設定の設定\r
+UINT CcSetClientConfig(REMOTE_CLIENT *r, CLIENT_CONFIG *o)\r
+{\r
+       PACK *p, *ret;\r
+       UINT err = 0;\r
+       // 引数チェック\r
+       if (r == NULL || o == NULL)\r
+       {\r
+               return ERR_INTERNAL_ERROR;\r
+       }\r
+\r
+       p = NewPack();\r
+       OutRpcClientConfig(p, o);\r
+\r
+       ret = RpcCall(r->Rpc, "SetClientConfig", p);\r
+\r
+       if (RpcIsOk(ret) == false)\r
+       {\r
+               err = RpcGetError(ret);\r
+       }\r
+\r
+       FreePack(ret);\r
+\r
+       return err;\r
+}\r
+\r
+// クライアント設定の取得\r
+UINT CcGetClientConfig(REMOTE_CLIENT *r, CLIENT_CONFIG *o)\r
+{\r
+       PACK *ret;\r
+       UINT err = 0;\r
+       // 引数チェック\r
+       if (r == NULL || o == NULL)\r
+       {\r
+               return ERR_INTERNAL_ERROR;\r
+       }\r
+\r
+       ret = RpcCall(r->Rpc, "GetClientConfig", NULL);\r
+\r
+       if (RpcIsOk(ret))\r
+       {\r
+               InRpcClientConfig(o, ret);\r
+       }\r
+       else\r
+       {\r
+               err = RpcGetError(ret);\r
+       }\r
+\r
+       FreePack(ret);\r
+\r
+       return err;\r
+}\r
+\r
+// サービスをフォアグラウンドプロセスに設定する\r
+void CcSetServiceToForegroundProcess(REMOTE_CLIENT *r)\r
+{\r
+       // 引数チェック\r
+       if (r == NULL)\r
+       {\r
+               return;\r
+       }\r
+       // 廃止\r
+/*\r
+       if (r->Rpc != NULL && r->Rpc->Sock != NULL && r->Rpc->Sock->RemoteIP.addr[0] == 127)\r
+       {\r
+               if (OS_IS_WINDOWS_NT(GetOsInfo()->OsType) &&\r
+                       GET_KETA(GetOsInfo()->OsType, 100) >= 2)\r
+               {\r
+                       // Windows 2000 以降でのみこの操作は行う\r
+                       RPC_CLIENT_VERSION v;\r
+                       Zero(&v, sizeof(v));\r
+\r
+                       if (r->ClientBuildInt == 0)\r
+                       {\r
+                               CcGetClientVersion(r, &v);\r
+                               r->ClientBuildInt = v.ClientBuildInt;\r
+                               r->ProcessId = v.ProcessId;\r
+                       }\r
+                       if (r->ProcessId != 0 && r->ClientBuildInt <= 5080)\r
+                       {\r
+#ifdef OS_WIN32\r
+                               // サービスプロセスをフォアグラウンドウインドウに設定する\r
+                               AllowFGWindow(v.ProcessId);\r
+#endif // OS_WIN32\r
+                       }\r
+               }\r
+       }*/\r
+}\r
+\r
+// 接続\r
+UINT CcConnect(REMOTE_CLIENT *r, RPC_CLIENT_CONNECT *connect)\r
+{\r
+       PACK *ret, *p;\r
+       UINT err = 0;\r
+       // 引数チェック\r
+       if (r == NULL || connect == NULL)\r
+       {\r
+               return ERR_INTERNAL_ERROR;\r
+       }\r
+\r
+       CcSetServiceToForegroundProcess(r);\r
+\r
+       p = NewPack();\r
+       OutRpcClientConnect(p, connect);\r
+\r
+       ret = RpcCall(r->Rpc, "Connect", p);\r
+\r
+       if (RpcIsOk(ret) == false)\r
+       {\r
+               err = RpcGetError(ret);\r
+       }\r
+\r
+       FreePack(ret);\r
+\r
+       return err;\r
+}\r
+\r
+// 切断\r
+UINT CcDisconnect(REMOTE_CLIENT *r, RPC_CLIENT_CONNECT *connect)\r
+{\r
+       PACK *ret, *p;\r
+       UINT err = 0;\r
+       // 引数チェック\r
+       if (r == NULL || connect == NULL)\r
+       {\r
+               return ERR_INTERNAL_ERROR;\r
+       }\r
+\r
+       CcSetServiceToForegroundProcess(r);\r
+\r
+       p = NewPack();\r
+       OutRpcClientConnect(p, connect);\r
+\r
+       ret = RpcCall(r->Rpc, "Disconnect", p);\r
+\r
+       if (RpcIsOk(ret) == false)\r
+       {\r
+               err = RpcGetError(ret);\r
+       }\r
+\r
+       FreePack(ret);\r
+\r
+       return err;\r
+}\r
+\r
+// アカウント状況の取得\r
+UINT CcGetAccountStatus(REMOTE_CLIENT *r, RPC_CLIENT_GET_CONNECTION_STATUS *st)\r
+{\r
+       PACK *ret, *p;\r
+       UINT err = 0;\r
+       // 引数チェック\r
+       if (r == NULL || st == NULL)\r
+       {\r
+               return ERR_INTERNAL_ERROR;\r
+       }\r
+\r
+       p = NewPack();\r
+       OutRpcClientGetConnectionStatus(p, st);\r
+\r
+       ret = RpcCall(r->Rpc, "GetAccountStatus", p);\r
+\r
+       if (RpcIsOk(ret))\r
+       {\r
+               InRpcClientGetConnectionStatus(st, ret);\r
+       }\r
+       else\r
+       {\r
+               err = RpcGetError(ret);\r
+       }\r
+\r
+       FreePack(ret);\r
+\r
+       return err;\r
+}\r
+\r
+\r
+// クライアントサービスが接続マネージャに対して通知を送信する\r
+void CiNotify(CLIENT *c)\r
+{\r
+       // 引数チェック\r
+       if (c == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       // すべての通知イベントを起動する\r
+       LockList(c->NotifyCancelList);\r
+       {\r
+               UINT i;\r
+               for (i = 0;i < LIST_NUM(c->NotifyCancelList);i++)\r
+               {\r
+                       CANCEL *cancel = LIST_DATA(c->NotifyCancelList, i);\r
+                       Cancel(cancel);\r
+               }\r
+       }\r
+       UnlockList(c->NotifyCancelList);\r
+}\r
+\r
+// RPC_CLIENT_ENUM_ACCOUNT の解放\r
+void CiFreeClientEnumAccount(RPC_CLIENT_ENUM_ACCOUNT *a)\r
+{\r
+       UINT i;\r
+       // 引数チェック\r
+       if (a == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       for (i = 0;i < a->NumItem;i++)\r
+       {\r
+               RPC_CLIENT_ENUM_ACCOUNT_ITEM *e = a->Items[i];\r
+               Free(e);\r
+       }\r
+       Free(a->Items);\r
+}\r
+\r
+\r
+// 一定時間ごとに設定ファイルを保存するスレッド\r
+void CiSaverThread(THREAD *t, void *param)\r
+{\r
+       CLIENT *c = (CLIENT *)param;\r
+       // 引数チェック\r
+       if (t == NULL || param == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       NoticeThreadInit(t);\r
+\r
+       // 一定時間待つ\r
+       while (c->Halt == false)\r
+       {\r
+               Wait(c->SaverHalter, CLIENT_SAVER_INTERVAL);\r
+\r
+               // 保存\r
+               CiSaveConfigurationFile(c);\r
+       }\r
+}\r
+\r
+// 設定データ自動保存の初期化\r
+void CiInitSaver(CLIENT *c)\r
+{\r
+       // 引数チェック\r
+       if (c == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       c->SaverHalter = NewEvent();\r
+\r
+       c->SaverThread = NewThread(CiSaverThread, c);\r
+       WaitThreadInit(c->SaverThread);\r
+}\r
+\r
+// 設定データ自動保存の解放\r
+void CiFreeSaver(CLIENT *c)\r
+{\r
+       // 引数チェック\r
+       if (c == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       c->Halt = true;\r
+       Set(c->SaverHalter);\r
+       WaitThread(c->SaverThread, INFINITE);\r
+       ReleaseThread(c->SaverThread);\r
+\r
+       ReleaseEvent(c->SaverHalter);\r
+}\r
+\r
+// CM_SETTING\r
+void InRpcCmSetting(CM_SETTING *c, PACK *p)\r
+{\r
+       // 引数チェック\r
+       if (c == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Zero(c, sizeof(CM_SETTING));\r
+       c->EasyMode = PackGetBool(p, "EasyMode");\r
+       c->LockMode = PackGetBool(p, "LockMode");\r
+       PackGetData2(p, "HashedPassword", c->HashedPassword, sizeof(c->HashedPassword));\r
+}\r
+void OutRpcCmSetting(PACK *p, CM_SETTING *c)\r
+{\r
+       // 引数チェック\r
+       if (c == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       PackAddBool(p, "EasyMode", c->EasyMode);\r
+       PackAddBool(p, "LockMode", c->LockMode);\r
+       PackAddData(p, "HashedPassword", c->HashedPassword, sizeof(c->HashedPassword));\r
+}\r
+\r
+// CLIENT_CONFIG\r
+void InRpcClientConfig(CLIENT_CONFIG *c, PACK *p)\r
+{\r
+       // 引数チェック\r
+       if (c == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Zero(c, sizeof(CLIENT_CONFIG));\r
+       c->UseKeepConnect = PackGetInt(p, "UseKeepConnect") == 0 ? false : true;\r
+       c->KeepConnectPort = PackGetInt(p, "KeepConnectPort");\r
+       c->KeepConnectProtocol = PackGetInt(p, "KeepConnectProtocol");\r
+       c->KeepConnectInterval = PackGetInt(p, "KeepConnectInterval");\r
+       c->AllowRemoteConfig = PackGetInt(p, "AllowRemoteConfig") == 0 ? false : true;\r
+       PackGetStr(p, "KeepConnectHost", c->KeepConnectHost, sizeof(c->KeepConnectHost));\r
+}\r
+void OutRpcClientConfig(PACK *p, CLIENT_CONFIG *c)\r
+{\r
+       // 引数チェック\r
+       if (c == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       PackAddInt(p, "UseKeepConnect", c->UseKeepConnect);\r
+       PackAddInt(p, "KeepConnectPort", c->KeepConnectPort);\r
+       PackAddInt(p, "KeepConnectProtocol", c->KeepConnectProtocol);\r
+       PackAddInt(p, "KeepConnectInterval", c->KeepConnectInterval);\r
+       PackAddInt(p, "AllowRemoteConfig", c->AllowRemoteConfig);\r
+       PackAddStr(p, "KeepConnectHost", c->KeepConnectHost);\r
+}\r
+\r
+// RPC_CLIENT_VERSION\r
+void InRpcClientVersion(RPC_CLIENT_VERSION *ver, PACK *p)\r
+{\r
+       // 引数チェック\r
+       if (ver == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Zero(ver, sizeof(RPC_CLIENT_VERSION));\r
+       PackGetStr(p, "ClientProductName", ver->ClientProductName, sizeof(ver->ClientProductName));\r
+       PackGetStr(p, "ClientVersionString", ver->ClientVersionString, sizeof(ver->ClientVersionString));\r
+       PackGetStr(p, "ClientBuildInfoString", ver->ClientBuildInfoString, sizeof(ver->ClientBuildInfoString));\r
+       ver->ClientVerInt = PackGetInt(p, "ClientVerInt");\r
+       ver->ClientBuildInt = PackGetInt(p, "ClientBuildInt");\r
+       ver->ProcessId = PackGetInt(p, "ProcessId");\r
+       ver->OsType = PackGetInt(p, "OsType");\r
+}\r
+void OutRpcClientVersion(PACK *p, RPC_CLIENT_VERSION *ver)\r
+{\r
+       // 引数チェック\r
+       if (ver == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       PackAddStr(p, "ClientProductName", ver->ClientProductName);\r
+       PackAddStr(p, "ClientVersionString", ver->ClientVersionString);\r
+       PackAddStr(p, "ClientBuildInfoString", ver->ClientBuildInfoString);\r
+       PackAddInt(p, "ClientVerInt", ver->ClientVerInt);\r
+       PackAddInt(p, "ClientBuildInt", ver->ClientBuildInt);\r
+       PackAddInt(p, "ProcessId", ver->ProcessId);\r
+       PackAddInt(p, "OsType", ver->OsType);\r
+}\r
+\r
+// RPC_CLIENT_PASSWORD\r
+void InRpcClientPassword(RPC_CLIENT_PASSWORD *pw, PACK *p)\r
+{\r
+       // 引数チェック\r
+       if (pw == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Zero(pw, sizeof(RPC_CLIENT_PASSWORD));\r
+       PackGetStr(p, "Password", pw->Password, sizeof(pw->Password));\r
+       pw->PasswordRemoteOnly = PackGetInt(p, "PasswordRemoteOnly");\r
+}\r
+void OutRpcClientPassword(PACK *p, RPC_CLIENT_PASSWORD *pw)\r
+{\r
+       // 引数チェック\r
+       if (pw == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       PackAddStr(p, "Password", pw->Password);\r
+       PackAddInt(p, "PasswordRemoteOnly", pw->PasswordRemoteOnly);\r
+}\r
+\r
+// RPC_CLIENT_PASSWORD_SETTING\r
+void InRpcClientPasswordSetting(RPC_CLIENT_PASSWORD_SETTING *a, PACK *p)\r
+{\r
+       // 引数チェック\r
+       if (a == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Zero(a, sizeof(RPC_CLIENT_PASSWORD_SETTING));\r
+\r
+       a->IsPasswordPresented = PackGetInt(p, "IsPasswordPresented") == 0 ? false : true;\r
+       a->PasswordRemoteOnly = PackGetInt(p, "PasswordRemoteOnly") == 0 ? false : true;\r
+}\r
+void OutRpcClientPasswordSetting(PACK *p, RPC_CLIENT_PASSWORD_SETTING *a)\r
+{\r
+       // 引数チェック\r
+       if (a == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       PackAddInt(p, "IsPasswordPresented", a->IsPasswordPresented);\r
+       PackAddInt(p, "PasswordRemoteOnly", a->PasswordRemoteOnly);\r
+}\r
+\r
+// RPC_CLIENT_ENUM_CA\r
+void InRpcClientEnumCa(RPC_CLIENT_ENUM_CA *e, PACK *p)\r
+{\r
+       UINT i;\r
+       // 引数チェック\r
+       if (e == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Zero(e, sizeof(RPC_CLIENT_ENUM_CA));\r
+       e->NumItem = PackGetNum(p, "NumItem");\r
+\r
+       e->Items = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_CA_ITEM *) * e->NumItem);\r
+       for (i = 0;i < e->NumItem;i++)\r
+       {\r
+               RPC_CLIENT_ENUM_CA_ITEM *item = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_CA_ITEM));\r
+               e->Items[i] = item;\r
+\r
+               item->Key = PackGetIntEx(p, "Key", i);\r
+               PackGetUniStrEx(p, "SubjectName", item->SubjectName, sizeof(item->SubjectName), i);\r
+               PackGetUniStrEx(p, "IssuerName", item->IssuerName, sizeof(item->IssuerName), i);\r
+               item->Expires = PackGetInt64Ex(p, "Expires", i);\r
+       }\r
+}\r
+void OutRpcClientEnumCa(PACK *p, RPC_CLIENT_ENUM_CA *e)\r
+{\r
+       UINT i;\r
+       // 引数チェック\r
+       if (e == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       PackAddNum(p, "NumItem", e->NumItem);\r
+\r
+       for (i = 0;i < e->NumItem;i++)\r
+       {\r
+               RPC_CLIENT_ENUM_CA_ITEM *item = e->Items[i];\r
+               PackAddIntEx(p, "Key", item->Key, i, e->NumItem);\r
+               PackAddUniStrEx(p, "SubjectName", item->SubjectName, i, e->NumItem);\r
+               PackAddUniStrEx(p, "IssuerName", item->IssuerName, i, e->NumItem);\r
+               PackAddInt64Ex(p, "Expires", item->Expires, i, e->NumItem);\r
+       }\r
+}\r
+\r
+// RPC_GET_ISSUER\r
+void InRpcGetIssuer(RPC_GET_ISSUER *c, PACK *p)\r
+{\r
+       BUF *b;\r
+       // 引数チェック\r
+       if (c == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Zero(c, sizeof(RPC_GET_ISSUER));\r
+       b = PackGetBuf(p, "x");\r
+       if (b != NULL)\r
+       {\r
+               if (c->x != NULL)\r
+               {\r
+                       FreeX(c->x);\r
+               }\r
+               c->x = BufToX(b, false);\r
+               FreeBuf(b);\r
+       }\r
+\r
+       b = PackGetBuf(p, "issuer_x");\r
+       if (b != NULL)\r
+       {\r
+               c->issuer_x = BufToX(b, false);\r
+               FreeBuf(b);\r
+       }\r
+}\r
+void OutRpcGetIssuer(PACK *p, RPC_GET_ISSUER *c)\r
+{\r
+       BUF *b;\r
+       // 引数チェック\r
+       if (p == NULL || c == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       if (c->x != NULL)\r
+       {\r
+               b = XToBuf(c->x, false);\r
+\r
+               PackAddBuf(p, "x", b);\r
+               FreeBuf(b);\r
+       }\r
+\r
+       if (c->issuer_x != NULL)\r
+       {\r
+               b = XToBuf(c->issuer_x, false);\r
+\r
+               PackAddBuf(p, "issuer_x", b);\r
+               FreeBuf(b);\r
+       }\r
+}\r
+\r
+// TRAFFIC_EX\r
+void InRpcTrafficEx(TRAFFIC *t, PACK *p, UINT i)\r
+{\r
+       // 引数チェック\r
+       if (t == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Zero(t, sizeof(TRAFFIC));\r
+       t->Recv.BroadcastBytes = PackGetInt64Ex(p, "Ex.Recv.BroadcastBytes", i);\r
+       t->Recv.BroadcastCount = PackGetInt64Ex(p, "Ex.Recv.BroadcastCount", i);\r
+       t->Recv.UnicastBytes = PackGetInt64Ex(p, "Ex.Recv.UnicastBytes", i);\r
+       t->Recv.UnicastCount = PackGetInt64Ex(p, "Ex.Recv.UnicastCount", i);\r
+       t->Send.BroadcastBytes = PackGetInt64Ex(p, "Ex.Send.BroadcastBytes", i);\r
+       t->Send.BroadcastCount = PackGetInt64Ex(p, "Ex.Send.BroadcastCount", i);\r
+       t->Send.UnicastBytes = PackGetInt64Ex(p, "Ex.Send.UnicastBytes", i);\r
+       t->Send.UnicastCount = PackGetInt64Ex(p, "Ex.Send.UnicastCount", i);\r
+}\r
+void OutRpcTrafficEx(TRAFFIC *t, PACK *p, UINT i, UINT num)\r
+{\r
+       // 引数チェック\r
+       if (t == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       PackAddInt64Ex(p, "Ex.Recv.BroadcastBytes", t->Recv.BroadcastBytes, i, num);\r
+       PackAddInt64Ex(p, "Ex.Recv.BroadcastCount", t->Recv.BroadcastCount, i, num);\r
+       PackAddInt64Ex(p, "Ex.Recv.UnicastBytes", t->Recv.UnicastBytes, i, num);\r
+       PackAddInt64Ex(p, "Ex.Recv.UnicastCount", t->Recv.UnicastCount, i, num);\r
+       PackAddInt64Ex(p, "Ex.Send.BroadcastBytes", t->Send.BroadcastBytes, i, num);\r
+       PackAddInt64Ex(p, "Ex.Send.BroadcastCount", t->Send.BroadcastCount, i, num);\r
+       PackAddInt64Ex(p, "Ex.Send.UnicastBytes", t->Send.UnicastBytes, i, num);\r
+       PackAddInt64Ex(p, "Ex.Send.UnicastCount", t->Send.UnicastCount, i, num);\r
+}\r
+\r
+// TRAFFIC\r
+void InRpcTraffic(TRAFFIC *t, PACK *p)\r
+{\r
+       // 引数チェック\r
+       if (t == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Zero(t, sizeof(TRAFFIC));\r
+       t->Recv.BroadcastBytes = PackGetInt64(p, "Recv.BroadcastBytes");\r
+       t->Recv.BroadcastCount = PackGetInt64(p, "Recv.BroadcastCount");\r
+       t->Recv.UnicastBytes = PackGetInt64(p, "Recv.UnicastBytes");\r
+       t->Recv.UnicastCount = PackGetInt64(p, "Recv.UnicastCount");\r
+       t->Send.BroadcastBytes = PackGetInt64(p, "Send.BroadcastBytes");\r
+       t->Send.BroadcastCount = PackGetInt64(p, "Send.BroadcastCount");\r
+       t->Send.UnicastBytes = PackGetInt64(p, "Send.UnicastBytes");\r
+       t->Send.UnicastCount = PackGetInt64(p, "Send.UnicastCount");\r
+}\r
+void OutRpcTraffic(PACK *p, TRAFFIC *t)\r
+{\r
+       // 引数チェック\r
+       if (t == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       PackAddInt64(p, "Recv.BroadcastBytes", t->Recv.BroadcastBytes);\r
+       PackAddInt64(p, "Recv.BroadcastCount", t->Recv.BroadcastCount);\r
+       PackAddInt64(p, "Recv.UnicastBytes", t->Recv.UnicastBytes);\r
+       PackAddInt64(p, "Recv.UnicastCount", t->Recv.UnicastCount);\r
+       PackAddInt64(p, "Send.BroadcastBytes", t->Send.BroadcastBytes);\r
+       PackAddInt64(p, "Send.BroadcastCount", t->Send.BroadcastCount);\r
+       PackAddInt64(p, "Send.UnicastBytes", t->Send.UnicastBytes);\r
+       PackAddInt64(p, "Send.UnicastCount", t->Send.UnicastCount);\r
+}\r
+\r
+// RPC_CERT\r
+void InRpcCert(RPC_CERT *c, PACK *p)\r
+{\r
+       BUF *b;\r
+       // 引数チェック\r
+       if (c == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Zero(c, sizeof(RPC_CERT));\r
+       b = PackGetBuf(p, "x");\r
+       if (b == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       c->x = BufToX(b, false);\r
+       FreeBuf(b);\r
+}\r
+void OutRpcCert(PACK *p, RPC_CERT *c)\r
+{\r
+       BUF *b;\r
+       // 引数チェック\r
+       if (p == NULL || c == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       if (c->x != NULL)\r
+       {\r
+               b = XToBuf(c->x, false);\r
+\r
+               PackAddBuf(p, "x", b);\r
+\r
+               FreeBuf(b);\r
+       }\r
+}\r
+\r
+// RPC_CLIENT_DELETE_CA\r
+void InRpcClientDeleteCa(RPC_CLIENT_DELETE_CA *c, PACK *p)\r
+{\r
+       // 引数チェック\r
+       if (c == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Zero(c, sizeof(RPC_CLIENT_DELETE_CA));\r
+       c->Key = PackGetInt(p, "Key");\r
+}\r
+void OutRpcClientDeleteCa(PACK *p, RPC_CLIENT_DELETE_CA *c)\r
+{\r
+       // 引数チェック\r
+       if (c == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       PackAddInt(p, "Key", c->Key);\r
+}\r
+\r
+// RPC_GET_CA\r
+void InRpcGetCa(RPC_GET_CA *c, PACK *p)\r
+{\r
+       BUF *b;\r
+       // 引数チェック\r
+       if (c == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Zero(c, sizeof(RPC_GET_CA));\r
+\r
+       c->Key = PackGetInt(p, "Key");\r
+\r
+       b = PackGetBuf(p, "x");\r
+       if (b != NULL)\r
+       {\r
+               c->x = BufToX(b, false);\r
+\r
+               FreeBuf(b);\r
+       }\r
+}\r
+void OutRpcGetCa(PACK *p, RPC_GET_CA *c)\r
+{\r
+       // 引数チェック\r
+       if (c == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       PackAddInt(p, "Key", c->Key);\r
+\r
+       if (c->x != NULL)\r
+       {\r
+               BUF *b = XToBuf(c->x, false);\r
+\r
+               PackAddBuf(p, "x", b);\r
+\r
+               FreeBuf(b);\r
+       }\r
+}\r
+\r
+// RPC_CLIENT_ENUM_SECURE\r
+void InRpcClientEnumSecure(RPC_CLIENT_ENUM_SECURE *e, PACK *p)\r
+{\r
+       UINT i;\r
+       // 引数チェック\r
+       if (e == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Zero(e, sizeof(RPC_CLIENT_ENUM_SECURE));\r
+\r
+       e->NumItem = PackGetNum(p, "NumItem");\r
+       e->Items = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_SECURE_ITEM *) * e->NumItem);\r
+       for (i = 0;i < e->NumItem;i++)\r
+       {\r
+               RPC_CLIENT_ENUM_SECURE_ITEM *item = e->Items[i] = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_SECURE_ITEM));\r
+\r
+               item->DeviceId = PackGetIntEx(p, "DeviceId", i);\r
+               item->Type = PackGetIntEx(p, "Type", i);\r
+               PackGetStrEx(p, "DeviceName", item->DeviceName, sizeof(item->DeviceName), i);\r
+               PackGetStrEx(p, "Manufacturer", item->Manufacturer, sizeof(item->Manufacturer), i);\r
+       }\r
+}\r
+void OutRpcClientEnumSecure(PACK *p, RPC_CLIENT_ENUM_SECURE *e)\r
+{\r
+       UINT i;\r
+       // 引数チェック\r
+       if (e == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       PackAddNum(p, "NumItem", e->NumItem);\r
+\r
+       for (i = 0;i < e->NumItem;i++)\r
+       {\r
+               RPC_CLIENT_ENUM_SECURE_ITEM *item = e->Items[i];\r
+\r
+               PackAddIntEx(p, "DeviceId", item->DeviceId, i, e->NumItem);\r
+               PackAddIntEx(p, "Type", item->Type, i, e->NumItem);\r
+               PackAddStrEx(p, "DeviceName", item->DeviceName, i, e->NumItem);\r
+               PackAddStrEx(p, "Manufacturer", item->Manufacturer, i, e->NumItem);\r
+       }\r
+}\r
+\r
+// RPC_USE_SECURE\r
+void InRpcUseSecure(RPC_USE_SECURE *u, PACK *p)\r
+{\r
+       // 引数チェック\r
+       if (u == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Zero(u, sizeof(RPC_USE_SECURE));\r
+       u->DeviceId = PackGetInt(p, "DeviceId");\r
+}\r
+void OutRpcUseSecure(PACK *p, RPC_USE_SECURE *u)\r
+{\r
+       // 引数チェック\r
+       if (u == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       PackAddInt(p, "DeviceId", u->DeviceId);\r
+}\r
+\r
+// RPC_ENUM_OBJECT_IN_SECURE の解放\r
+void CiFreeEnumObjectInSecure(RPC_ENUM_OBJECT_IN_SECURE *a)\r
+{\r
+       UINT i;\r
+       // 引数チェック\r
+       if (a == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       for (i = 0;i < a->NumItem;i++)\r
+       {\r
+               Free(a->ItemName[i]);\r
+       }\r
+       Free(a->ItemName);\r
+       Free(a->ItemType);\r
+}\r
+\r
+// RPC_ENUM_OBJECT_IN_SECURE\r
+void InRpcEnumObjectInSecure(RPC_ENUM_OBJECT_IN_SECURE *e, PACK *p)\r
+{\r
+       UINT i;\r
+       // 引数チェック\r
+       if (e == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Zero(e, sizeof(RPC_ENUM_OBJECT_IN_SECURE));\r
+\r
+       e->NumItem = PackGetNum(p, "NumItem");\r
+       e->hWnd = PackGetInt(p, "hWnd");\r
+       e->ItemName = ZeroMalloc(sizeof(char *) * e->NumItem);\r
+       e->ItemType = ZeroMalloc(sizeof(bool) * e->NumItem);\r
+\r
+       for (i = 0;i < e->NumItem;i++)\r
+       {\r
+               char name[MAX_SIZE];\r
+\r
+               Zero(name, sizeof(name));\r
+               PackGetStrEx(p, "ItemName", name, sizeof(name), i);\r
+               e->ItemName[i] = CopyStr(name);\r
+\r
+               e->ItemType[i] = PackGetIntEx(p, "ItemType", i) ? true : false;\r
+       }\r
+}\r
+void OutRpcEnumObjectInSecure(PACK *p, RPC_ENUM_OBJECT_IN_SECURE *e)\r
+{\r
+       UINT i;\r
+       // 引数チェック\r
+       if (e == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       PackAddNum(p, "NumItem", e->NumItem);\r
+       PackAddInt(p, "hWnd", e->hWnd);\r
+\r
+       for (i = 0;i < e->NumItem;i++)\r
+       {\r
+               PackAddStrEx(p, "ItemName", e->ItemName[i], i, e->NumItem);\r
+               PackAddIntEx(p, "ItemType", e->ItemType[i], i, e->NumItem);\r
+       }\r
+}\r
+\r
+// RPC_CLIENT_CREATE_VLAN\r
+void InRpcCreateVLan(RPC_CLIENT_CREATE_VLAN *v, PACK *p)\r
+{\r
+       // 引数チェック\r
+       if (v == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Zero(v, sizeof(RPC_CLIENT_CREATE_VLAN));\r
+       PackGetStr(p, "DeviceName", v->DeviceName, sizeof(v->DeviceName));\r
+}\r
+void OutRpcCreateVLan(PACK *p, RPC_CLIENT_CREATE_VLAN *v)\r
+{\r
+       // 引数チェック\r
+       if (v == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       PackAddStr(p, "DeviceName", v->DeviceName);\r
+}\r
+\r
+// RPC_CLIENT_GET_VLAN\r
+void InRpcClientGetVLan(RPC_CLIENT_GET_VLAN *v, PACK *p)\r
+{\r
+       // 引数チェック\r
+       if (v == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Zero(v, sizeof(RPC_CLIENT_GET_VLAN));\r
+       PackGetStr(p, "DeviceName", v->DeviceName, sizeof(v->DeviceName));\r
+       v->Enabled = PackGetInt(p, "Enabled") ? true : false;\r
+       PackGetStr(p, "MacAddress", v->MacAddress, sizeof(v->MacAddress));\r
+       PackGetStr(p, "Version", v->Version, sizeof(v->Version));\r
+       PackGetStr(p, "FileName", v->FileName, sizeof(v->FileName));\r
+       PackGetStr(p, "Guid", v->Guid, sizeof(v->Guid));\r
+}\r
+void OutRpcClientGetVLan(PACK *p, RPC_CLIENT_GET_VLAN *v)\r
+{\r
+       // 引数チェック\r
+       if (v == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       PackAddStr(p, "DeviceName", v->DeviceName);\r
+       PackAddInt(p, "Enabled", v->Enabled);\r
+       PackAddStr(p, "MacAddress", v->MacAddress);\r
+       PackAddStr(p, "Version", v->Version);\r
+       PackAddStr(p, "FileName", v->FileName);\r
+       PackAddStr(p, "Guid", v->Guid);\r
+}\r
+\r
+// RPC_CLIENT_SET_VLAN\r
+void InRpcClientSetVLan(RPC_CLIENT_SET_VLAN *v, PACK *p)\r
+{\r
+       // 引数チェック\r
+       if (v == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Zero(v, sizeof(RPC_CLIENT_SET_VLAN));\r
+       PackGetStr(p, "DeviceName", v->DeviceName, sizeof(v->DeviceName));\r
+       PackGetStr(p, "MacAddress", v->MacAddress, sizeof(v->MacAddress));\r
+}\r
+void OutRpcClientSetVLan(PACK *p, RPC_CLIENT_SET_VLAN *v)\r
+{\r
+       // 引数チェック\r
+       if (v == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       PackAddStr(p, "DeviceName", v->DeviceName);\r
+       PackAddStr(p, "MacAddress", v->MacAddress);\r
+}\r
+\r
+// RPC_CLIENT_ENUM_VLAN\r
+void InRpcClientEnumVLan(RPC_CLIENT_ENUM_VLAN *v, PACK *p)\r
+{\r
+       UINT i;\r
+       // 引数チェック\r
+       if (v == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Zero(v, sizeof(RPC_CLIENT_ENUM_VLAN));\r
+       v->NumItem = PackGetNum(p, "NumItem");\r
+       v->Items = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_VLAN_ITEM *) * v->NumItem);\r
+\r
+       for (i = 0;i < v->NumItem;i++)\r
+       {\r
+               RPC_CLIENT_ENUM_VLAN_ITEM *item = v->Items[i] =\r
+                       ZeroMalloc(sizeof(RPC_CLIENT_ENUM_VLAN_ITEM));\r
+\r
+               PackGetStrEx(p, "DeviceName", item->DeviceName, sizeof(item->DeviceName), i);\r
+               item->Enabled = PackGetIntEx(p, "Enabled", i) ? true : false;\r
+               PackGetStrEx(p, "MacAddress", item->MacAddress, sizeof(item->MacAddress), i);\r
+               PackGetStrEx(p, "Version", item->Version, sizeof(item->Version), i);\r
+       }\r
+}\r
+void OutRpcClientEnumVLan(PACK *p, RPC_CLIENT_ENUM_VLAN *v)\r
+{\r
+       UINT i;\r
+       // 引数チェック\r
+       if (v == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       PackAddNum(p, "NumItem", v->NumItem);\r
+\r
+       for (i = 0;i < v->NumItem;i++)\r
+       {\r
+               RPC_CLIENT_ENUM_VLAN_ITEM *item = v->Items[i];\r
+\r
+               PackAddStrEx(p, "DeviceName", item->DeviceName, i, v->NumItem);\r
+               PackAddIntEx(p, "Enabled", item->Enabled, i, v->NumItem);\r
+               PackAddStrEx(p, "MacAddress", item->MacAddress, i, v->NumItem);\r
+               PackAddStrEx(p, "Version", item->Version, i, v->NumItem);\r
+       }\r
+}\r
+\r
+// CLIENT_OPTION\r
+void InRpcClientOption(CLIENT_OPTION *c, PACK *p)\r
+{\r
+       // 引数チェック\r
+       if (c == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Zero(c, sizeof(CLIENT_OPTION));\r
+\r
+       PackGetUniStr(p, "AccountName", c->AccountName, sizeof(c->AccountName));\r
+       PackGetStr(p, "Hostname", c->Hostname, sizeof(c->Hostname));\r
+       c->Port = PackGetInt(p, "Port");\r
+       c->PortUDP = PackGetInt(p, "PortUDP");\r
+       c->ProxyType = PackGetInt(p, "ProxyType");\r
+       c->ProxyPort = PackGetInt(p, "ProxyPort");\r
+       c->NumRetry = PackGetInt(p, "NumRetry");\r
+       c->RetryInterval = PackGetInt(p, "RetryInterval");\r
+       c->MaxConnection = PackGetInt(p, "MaxConnection");\r
+       c->AdditionalConnectionInterval = PackGetInt(p, "AdditionalConnectionInterval");\r
+       c->ConnectionDisconnectSpan = PackGetInt(p, "ConnectionDisconnectSpan");\r
+       c->HideStatusWindow = PackGetBool(p, "HideStatusWindow");\r
+       c->HideNicInfoWindow = PackGetBool(p, "HideNicInfoWindow");\r
+       c->DisableQoS = PackGetBool(p, "DisableQoS");\r
+       PackGetStr(p, "ProxyName", c->ProxyName, sizeof(c->ProxyName));\r
+       PackGetStr(p, "ProxyUsername", c->ProxyUsername, sizeof(c->ProxyUsername));\r
+       PackGetStr(p, "ProxyPassword", c->ProxyPassword, sizeof(c->ProxyPassword));\r
+       PackGetStr(p, "HubName", c->HubName, sizeof(c->HubName));\r
+       PackGetStr(p, "DeviceName", c->DeviceName, sizeof(c->DeviceName));\r
+       c->UseEncrypt = PackGetInt(p, "UseEncrypt") ? true : false;\r
+       c->UseCompress = PackGetInt(p, "UseCompress") ? true : false;\r
+       c->HalfConnection = PackGetInt(p, "HalfConnection") ? true : false;\r
+       c->NoRoutingTracking = PackGetInt(p, "NoRoutingTracking") ? true : false;\r
+       c->RequireMonitorMode = PackGetBool(p, "RequireMonitorMode");\r
+       c->RequireBridgeRoutingMode = PackGetBool(p, "RequireBridgeRoutingMode");\r
+       c->FromAdminPack = PackGetBool(p, "FromAdminPack");\r
+       c->NoTls1 = PackGetBool(p, "NoTls1");\r
+}\r
+void OutRpcClientOption(PACK *p, CLIENT_OPTION *c)\r
+{\r
+       // 引数チェック\r
+       if (c == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       PackAddUniStr(p, "AccountName", c->AccountName);\r
+       PackAddStr(p, "Hostname", c->Hostname);\r
+       PackAddStr(p, "ProxyName", c->ProxyName);\r
+       PackAddStr(p, "ProxyUsername", c->ProxyUsername);\r
+       PackAddStr(p, "ProxyPassword", c->ProxyPassword);\r
+       PackAddStr(p, "HubName", c->HubName);\r
+       PackAddStr(p, "DeviceName", c->DeviceName);\r
+       PackAddInt(p, "Port", c->Port);\r
+       PackAddInt(p, "PortUDP", c->PortUDP);\r
+       PackAddInt(p, "ProxyType", c->ProxyType);\r
+       PackAddInt(p, "ProxyPort", c->ProxyPort);\r
+       PackAddInt(p, "NumRetry", c->NumRetry);\r
+       PackAddInt(p, "RetryInterval", c->RetryInterval);\r
+       PackAddInt(p, "MaxConnection", c->MaxConnection);\r
+       PackAddInt(p, "UseEncrypt", c->UseEncrypt);\r
+       PackAddInt(p, "UseCompress", c->UseCompress);\r
+       PackAddInt(p, "HalfConnection", c->HalfConnection);\r
+       PackAddInt(p, "NoRoutingTracking", c->NoRoutingTracking);\r
+       PackAddInt(p, "AdditionalConnectionInterval", c->AdditionalConnectionInterval);\r
+       PackAddInt(p, "ConnectionDisconnectSpan", c->ConnectionDisconnectSpan);\r
+       PackAddBool(p, "HideStatusWindow", c->HideStatusWindow);\r
+       PackAddBool(p, "HideNicInfoWindow", c->HideNicInfoWindow);\r
+       PackAddBool(p, "RequireMonitorMode", c->RequireMonitorMode);\r
+       PackAddBool(p, "RequireBridgeRoutingMode", c->RequireBridgeRoutingMode);\r
+       PackAddBool(p, "DisableQoS", c->DisableQoS);\r
+       PackAddBool(p, "FromAdminPack", c->FromAdminPack);\r
+       PackAddBool(p, "NoTls1", c->NoTls1);\r
+}\r
+\r
+// CLIENT_AUTH\r
+void InRpcClientAuth(CLIENT_AUTH *c, PACK *p)\r
+{\r
+       BUF *b;\r
+       // 引数チェック\r
+       if (c == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Zero(c, sizeof(CLIENT_AUTH));\r
+       c->AuthType = PackGetInt(p, "AuthType");\r
+       PackGetStr(p, "Username", c->Username, sizeof(c->Username));\r
+\r
+       switch (c->AuthType)\r
+       {\r
+       case CLIENT_AUTHTYPE_ANONYMOUS:\r
+               break;\r
+\r
+       case CLIENT_AUTHTYPE_PASSWORD:\r
+               if (PackGetDataSize(p, "HashedPassword") == SHA1_SIZE)\r
+               {\r
+                       PackGetData(p, "HashedPassword", c->HashedPassword);\r
+               }\r
+               break;\r
+\r
+       case CLIENT_AUTHTYPE_PLAIN_PASSWORD:\r
+               PackGetStr(p, "PlainPassword", c->PlainPassword, sizeof(c->PlainPassword));\r
+               break;\r
+\r
+       case CLIENT_AUTHTYPE_CERT:\r
+               b = PackGetBuf(p, "ClientX");\r
+               if (b != NULL)\r
+               {\r
+                       c->ClientX = BufToX(b, false);\r
+                       FreeBuf(b);\r
+               }\r
+               b = PackGetBuf(p, "ClientK");\r
+               if (b != NULL)\r
+               {\r
+                       c->ClientK = BufToK(b, true, false, NULL);\r
+                       FreeBuf(b);\r
+               }\r
+               break;\r
+\r
+       case CLIENT_AUTHTYPE_SECURE:\r
+               PackGetStr(p, "SecurePublicCertName", c->SecurePublicCertName, sizeof(c->SecurePublicCertName));\r
+               PackGetStr(p, "SecurePrivateKeyName", c->SecurePrivateKeyName, sizeof(c->SecurePrivateKeyName));\r
+               break;\r
+       }\r
+}\r
+void OutRpcClientAuth(PACK *p, CLIENT_AUTH *c)\r
+{\r
+       BUF *b;\r
+       // 引数チェック\r
+       if (c == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       PackAddInt(p, "AuthType", c->AuthType);\r
+       PackAddStr(p, "Username", c->Username);\r
+\r
+       switch (c->AuthType)\r
+       {\r
+       case CLIENT_AUTHTYPE_ANONYMOUS:\r
+               break;\r
+\r
+       case CLIENT_AUTHTYPE_PASSWORD:\r
+               PackAddData(p, "HashedPassword", c->HashedPassword, SHA1_SIZE);\r
+               break;\r
+\r
+       case CLIENT_AUTHTYPE_PLAIN_PASSWORD:\r
+               PackAddStr(p, "PlainPassword", c->PlainPassword);\r
+               break;\r
+\r
+       case CLIENT_AUTHTYPE_CERT:\r
+               b = XToBuf(c->ClientX, false);\r
+               if (b != NULL)\r
+               {\r
+                       PackAddBuf(p, "ClientX", b);\r
+                       FreeBuf(b);\r
+               }\r
+               b = KToBuf(c->ClientK, false, NULL);\r
+               if (b != NULL)\r
+               {\r
+                       PackAddBuf(p, "ClientK", b);\r
+                       FreeBuf(b);\r
+               }\r
+               break;\r
+\r
+       case CLIENT_AUTHTYPE_SECURE:\r
+               PackAddStr(p, "SecurePublicCertName", c->SecurePublicCertName);\r
+               PackAddStr(p, "SecurePrivateKeyName", c->SecurePrivateKeyName);\r
+               break;\r
+       }\r
+}\r
+\r
+// RPC_CLIENT_CREATE_ACCOUNT\r
+void InRpcClientCreateAccount(RPC_CLIENT_CREATE_ACCOUNT *c, PACK *p)\r
+{\r
+       BUF *b;\r
+       // 引数チェック\r
+       if (c == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Zero(c, sizeof(RPC_CLIENT_CREATE_ACCOUNT));\r
+       c->ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));\r
+       c->ClientAuth = ZeroMalloc(sizeof(CLIENT_AUTH));\r
+\r
+       InRpcClientOption(c->ClientOption, p);\r
+       InRpcClientAuth(c->ClientAuth, p);\r
+\r
+       c->StartupAccount = PackGetInt(p, "StartupAccount") ? true : false;\r
+       c->CheckServerCert = PackGetInt(p, "CheckServerCert") ? true : false;\r
+       b = PackGetBuf(p, "ServerCert");\r
+       if (b != NULL)\r
+       {\r
+               c->ServerCert = BufToX(b, false);\r
+               FreeBuf(b);\r
+       }\r
+       PackGetData2(p, "ShortcutKey", c->ShortcutKey, sizeof(c->ShortcutKey));\r
+}\r
+void OutRpcClientCreateAccount(PACK *p, RPC_CLIENT_CREATE_ACCOUNT *c)\r
+{\r
+       BUF *b;\r
+       // 引数チェック\r
+       if (c == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       OutRpcClientOption(p, c->ClientOption);\r
+       OutRpcClientAuth(p, c->ClientAuth);\r
+\r
+       PackAddInt(p, "StartupAccount", c->StartupAccount);\r
+       PackAddInt(p, "CheckServerCert", c->CheckServerCert);\r
+       if (c->ServerCert != NULL)\r
+       {\r
+               b = XToBuf(c->ServerCert, false);\r
+               if (b != NULL)\r
+               {\r
+                       PackAddBuf(p, "ServerCert", b);\r
+                       FreeBuf(b);\r
+               }\r
+       }\r
+       PackAddData(p, "ShortcutKey", c->ShortcutKey, sizeof(c->ShortcutKey));\r
+}\r
+\r
+// RPC_CLIENT_ENUM_ACCOUNT\r
+void InRpcClientEnumAccount(RPC_CLIENT_ENUM_ACCOUNT *e, PACK *p)\r
+{\r
+       UINT i;\r
+       // 引数チェック\r
+       if (e == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Zero(e, sizeof(RPC_CLIENT_ENUM_ACCOUNT));\r
+\r
+       e->NumItem = PackGetNum(p, "NumItem");\r
+       e->Items = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_ACCOUNT_ITEM *) * e->NumItem);\r
+\r
+       for (i = 0;i < e->NumItem;i++)\r
+       {\r
+               RPC_CLIENT_ENUM_ACCOUNT_ITEM *item = e->Items[i] =\r
+                       ZeroMalloc(sizeof(RPC_CLIENT_ENUM_ACCOUNT_ITEM));\r
+\r
+               PackGetUniStrEx(p, "AccountName", item->AccountName, sizeof(item->AccountName), i);\r
+               PackGetStrEx(p, "UserName", item->UserName, sizeof(item->UserName), i);\r
+               PackGetStrEx(p, "ServerName", item->ServerName, sizeof(item->ServerName), i);\r
+               PackGetStrEx(p, "ProxyName", item->ProxyName, sizeof(item->ProxyName), i);\r
+               PackGetStrEx(p, "DeviceName", item->DeviceName, sizeof(item->DeviceName), i);\r
+               item->ProxyType = PackGetIntEx(p, "ProxyType", i);\r
+               item->Active = PackGetIntEx(p, "Active", i) ? true : false;\r
+               item->StartupAccount = PackGetIntEx(p, "StartupAccount", i) ? true : false;\r
+               item->Connected = PackGetBoolEx(p, "Connected", i);\r
+               item->Port = PackGetIntEx(p, "Port", i);\r
+               PackGetStrEx(p, "HubName", item->HubName, sizeof(item->HubName), i);\r
+               item->CreateDateTime = PackGetInt64Ex(p, "CreateDateTime", i);\r
+               item->UpdateDateTime = PackGetInt64Ex(p, "UpdateDateTime", i);\r
+               item->LastConnectDateTime = PackGetInt64Ex(p, "LastConnectDateTime", i);\r
+       }\r
+}\r
+void OutRpcClientEnumAccount(PACK *p, RPC_CLIENT_ENUM_ACCOUNT *e)\r
+{\r
+       UINT i;\r
+       // 引数チェック\r
+       if (e == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       PackAddNum(p, "NumItem", e->NumItem);\r
+\r
+       for (i = 0;i < e->NumItem;i++)\r
+       {\r
+               RPC_CLIENT_ENUM_ACCOUNT_ITEM *item = e->Items[i];\r
+\r
+               PackAddUniStrEx(p, "AccountName", item->AccountName, i, e->NumItem);\r
+               PackAddStrEx(p, "UserName", item->UserName, i, e->NumItem);\r
+               PackAddStrEx(p, "ServerName", item->ServerName, i, e->NumItem);\r
+               PackAddStrEx(p, "ProxyName", item->ProxyName, i, e->NumItem);\r
+               PackAddStrEx(p, "DeviceName", item->DeviceName, i, e->NumItem);\r
+               PackAddIntEx(p, "ProxyType", item->ProxyType, i, e->NumItem);\r
+               PackAddIntEx(p, "Active", item->Active, i, e->NumItem);\r
+               PackAddIntEx(p, "StartupAccount", item->StartupAccount, i, e->NumItem);\r
+               PackAddBoolEx(p, "Connected", item->Connected, i, e->NumItem);\r
+               PackAddIntEx(p, "Port", item->Port, i, e->NumItem);\r
+               PackAddStrEx(p, "HubName", item->HubName, i, e->NumItem);\r
+               PackAddInt64Ex(p, "CreateDateTime", item->CreateDateTime, i, e->NumItem);\r
+               PackAddInt64Ex(p, "UpdateDateTime", item->UpdateDateTime, i, e->NumItem);\r
+               PackAddInt64Ex(p, "LastConnectDateTime", item->LastConnectDateTime, i, e->NumItem);\r
+       }\r
+}\r
+\r
+// RPC_CLIENT_DELETE_ACCOUNT\r
+void InRpcClientDeleteAccount(RPC_CLIENT_DELETE_ACCOUNT *a, PACK *p)\r
+{\r
+       // 引数チェック\r
+       if (a == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Zero(a, sizeof(RPC_CLIENT_DELETE_ACCOUNT));\r
+       PackGetUniStr(p, "AccountName", a->AccountName, sizeof(a->AccountName));\r
+}\r
+void OutRpcClientDeleteAccount(PACK *p, RPC_CLIENT_DELETE_ACCOUNT *a)\r
+{\r
+       // 引数チェック\r
+       if (a == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       PackAddUniStr(p, "AccountName", a->AccountName);\r
+}\r
+\r
+// RPC_RENAME_ACCOUNT\r
+void InRpcRenameAccount(RPC_RENAME_ACCOUNT *a, PACK *p)\r
+{\r
+       // 引数チェック\r
+       if (a == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Zero(a, sizeof(RPC_RENAME_ACCOUNT));\r
+\r
+       PackGetUniStr(p, "OldName", a->OldName, sizeof(a->OldName));\r
+       PackGetUniStr(p, "NewName", a->NewName, sizeof(a->NewName));\r
+}\r
+void OutRpcRenameAccount(PACK *p, RPC_RENAME_ACCOUNT *a)\r
+{\r
+       // 引数チェック\r
+       if (a == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       PackAddUniStr(p, "OldName", a->OldName);\r
+       PackAddUniStr(p, "NewName", a->NewName);\r
+}\r
+\r
+// RPC_CLIENT_GET_ACCOUNT\r
+void InRpcClientGetAccount(RPC_CLIENT_GET_ACCOUNT *c, PACK *p)\r
+{\r
+       BUF *b;\r
+       // 引数チェック\r
+       if (c == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Zero(c, sizeof(RPC_CLIENT_GET_ACCOUNT));\r
+\r
+       c->ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));\r
+       c->ClientAuth = ZeroMalloc(sizeof(CLIENT_AUTH));\r
+\r
+       PackGetUniStr(p, "AccountName", c->AccountName, sizeof(c->AccountName));\r
+       c->StartupAccount = PackGetInt(p, "StartupAccount") ? true : false;\r
+       c->CheckServerCert = PackGetInt(p, "CheckServerCert") ? true : false;\r
+       b = PackGetBuf(p, "ServerCert");\r
+       if (b != NULL)\r
+       {\r
+               c->ServerCert = BufToX(b, false);\r
+               FreeBuf(b);\r
+       }\r
+\r
+       InRpcClientOption(c->ClientOption, p);\r
+       InRpcClientAuth(c->ClientAuth, p);\r
+\r
+       c->CreateDateTime = PackGetInt64(p, "CreateDateTime");\r
+       c->UpdateDateTime = PackGetInt64(p, "UpdateDateTime");\r
+       c->LastConnectDateTime = PackGetInt64(p, "LastConnectDateTime");\r
+\r
+       PackGetData2(p, "ShortcutKey", c->ShortcutKey, SHA1_SIZE);\r
+}\r
+void OutRpcClientGetAccount(PACK *p, RPC_CLIENT_GET_ACCOUNT *c)\r
+{\r
+       BUF *b;\r
+       // 引数チェック\r
+       if (c == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       PackAddUniStr(p, "AccountName", c->AccountName);\r
+       PackAddInt(p, "StartupAccount", c->StartupAccount);\r
+       PackAddInt(p, "CheckServerCert", c->CheckServerCert);\r
+\r
+       if (c->ServerCert != NULL)\r
+       {\r
+               b = XToBuf(c->ServerCert, false);\r
+               if (b != NULL)\r
+               {\r
+                       PackAddBuf(p, "ServerCert", b);\r
+                       FreeBuf(b);\r
+               }\r
+       }\r
+\r
+       OutRpcClientOption(p, c->ClientOption);\r
+       OutRpcClientAuth(p, c->ClientAuth);\r
+\r
+       PackAddData(p, "ShortcutKey", c->ShortcutKey, SHA1_SIZE);\r
+\r
+       PackAddInt64(p, "CreateDateTime", c->CreateDateTime);\r
+       PackAddInt64(p, "UpdateDateTime", c->UpdateDateTime);\r
+       PackAddInt64(p, "LastConnectDateTime", c->LastConnectDateTime);\r
+}\r
+\r
+// RPC_CLIENT_CONNECT\r
+void InRpcClientConnect(RPC_CLIENT_CONNECT *c, PACK *p)\r
+{\r
+       // 引数チェック\r
+       if (c == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Zero(c, sizeof(RPC_CLIENT_CONNECT));\r
+\r
+       PackGetUniStr(p, "AccountName", c->AccountName, sizeof(c->AccountName));\r
+}\r
+void OutRpcClientConnect(PACK *p, RPC_CLIENT_CONNECT *c)\r
+{\r
+       // 引数チェック\r
+       if (c == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       PackAddUniStr(p, "AccountName", c->AccountName);\r
+}\r
+\r
+// POLICY\r
+void InRpcPolicy(POLICY *o, PACK *p)\r
+{\r
+       POLICY *pol;\r
+       // 引数チェック\r
+       if (o == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       pol = PackGetPolicy(p);\r
+       Copy(o, pol, sizeof(POLICY));\r
+       Free(pol);\r
+}\r
+void OutRpcPolicy(PACK *p, POLICY *o)\r
+{\r
+       // 引数チェック\r
+       if (o == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       PackAddPolicy(p, o);\r
+}\r
+\r
+// RPC_CLIENT_GET_CONNECTION_STATUS\r
+void InRpcClientGetConnectionStatus(RPC_CLIENT_GET_CONNECTION_STATUS *s, PACK *p)\r
+{\r
+       BUF *b;\r
+       // 引数チェック\r
+       if (s == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Zero(s, sizeof(RPC_CLIENT_GET_CONNECTION_STATUS));\r
+\r
+       PackGetUniStr(p, "AccountName", s->AccountName, sizeof(s->AccountName));\r
+\r
+       PackGetStr(p, "ServerName", s->ServerName, sizeof(s->ServerName));\r
+       PackGetStr(p, "ServerProductName", s->ServerProductName, sizeof(s->ServerProductName));\r
+       PackGetStr(p, "CipherName", s->CipherName, sizeof(s->CipherName));\r
+       PackGetStr(p, "SessionName", s->SessionName, sizeof(s->SessionName));\r
+       PackGetStr(p, "ConnectionName", s->ConnectionName, sizeof(s->ConnectionName));\r
+\r
+       if (PackGetDataSize(p, "SessionKey") == SHA1_SIZE)\r
+       {\r
+               PackGetData(p, "SessionKey", s->SessionKey);\r
+       }\r
+\r
+       s->SessionStatus = PackGetInt(p, "SessionStatus");\r
+       s->ServerPort = PackGetInt(p, "ServerPort");\r
+       s->ServerProductVer = PackGetInt(p, "ServerProductVer");\r
+       s->ServerProductBuild = PackGetInt(p, "ServerProductBuild");\r
+       s->NumConnectionsEatablished = PackGetInt(p, "NumConnectionsEatablished");\r
+       s->MaxTcpConnections = PackGetInt(p, "MaxTcpConnections");\r
+       s->NumTcpConnections = PackGetInt(p, "NumTcpConnections");\r
+       s->NumTcpConnectionsUpload = PackGetInt(p, "NumTcpConnectionsUpload");\r
+       s->NumTcpConnectionsDownload = PackGetInt(p, "NumTcpConnectionsDownload");\r
+\r
+       s->StartTime = PackGetInt64(p, "StartTime");\r
+       s->FirstConnectionEstablisiedTime = PackGetInt64(p, "FirstConnectionEstablisiedTime");\r
+       s->CurrentConnectionEstablishTime = PackGetInt64(p, "CurrentConnectionEstablishTime");\r
+       s->TotalSendSize = PackGetInt64(p, "TotalSendSize");\r
+       s->TotalRecvSize = PackGetInt64(p, "TotalRecvSize");\r
+       s->TotalSendSizeReal = PackGetInt64(p, "TotalSendSizeReal");\r
+       s->TotalRecvSizeReal = PackGetInt64(p, "TotalRecvSizeReal");\r
+\r
+       s->Active = PackGetInt(p, "Active") ? true : false;\r
+       s->Connected = PackGetInt(p, "Connected") ? true : false;\r
+       s->HalfConnection = PackGetInt(p, "HalfConnection") ? true : false;\r
+       s->QoS = PackGetInt(p, "QoS") ? true : false;\r
+       s->UseEncrypt = PackGetInt(p, "UseEncrypt") ? true : false;\r
+       s->UseCompress = PackGetInt(p, "UseCompress") ? true : false;\r
+\r
+       s->IsBridgeMode = PackGetBool(p, "IsBridgeMode");\r
+       s->IsMonitorMode = PackGetBool(p, "IsMonitorMode");\r
+\r
+       s->VLanId = PackGetInt(p, "VLanId");\r
+\r
+       b = PackGetBuf(p, "ServerX");\r
+       if (b != NULL)\r
+       {\r
+               s->ServerX = BufToX(b, false);\r
+               FreeBuf(b);\r
+       }\r
+\r
+       b = PackGetBuf(p, "ClientX");\r
+       if (b != NULL)\r
+       {\r
+               s->ClientX = BufToX(b, false);\r
+               FreeBuf(b);\r
+       }\r
+\r
+       InRpcPolicy(&s->Policy, p);\r
+\r
+       InRpcTraffic(&s->Traffic, p);\r
+}\r
+void OutRpcClientGetConnectionStatus(PACK *p, RPC_CLIENT_GET_CONNECTION_STATUS *c)\r
+{\r
+       BUF *b;\r
+       // 引数チェック\r
+       if (p == NULL || c == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       PackAddUniStr(p, "AccountName", c->AccountName);\r
+\r
+       PackAddStr(p, "ServerName", c->ServerName);\r
+       PackAddStr(p, "ServerProductName", c->ServerProductName);\r
+       PackAddStr(p, "CipherName", c->CipherName);\r
+       PackAddStr(p, "SessionName", c->SessionName);\r
+       PackAddStr(p, "ConnectionName", c->ConnectionName);\r
+\r
+       PackAddData(p, "SessionKey", c->SessionKey, SHA1_SIZE);\r
+\r
+       PackAddInt(p, "Active", c->Active);\r
+       PackAddInt(p, "Connected", c->Connected);\r
+       PackAddInt(p, "SessionStatus", c->SessionStatus);\r
+       PackAddInt(p, "ServerPort", c->ServerPort);\r
+       PackAddInt(p, "ServerProductVer", c->ServerProductVer);\r
+       PackAddInt(p, "ServerProductBuild", c->ServerProductBuild);\r
+       PackAddInt(p, "NumConnectionsEatablished", c->NumConnectionsEatablished);\r
+       PackAddInt(p, "HalfConnection", c->HalfConnection);\r
+       PackAddInt(p, "QoS", c->QoS);\r
+       PackAddInt(p, "MaxTcpConnections", c->MaxTcpConnections);\r
+       PackAddInt(p, "NumTcpConnections", c->NumTcpConnections);\r
+       PackAddInt(p, "NumTcpConnectionsUpload", c->NumTcpConnectionsUpload);\r
+       PackAddInt(p, "NumTcpConnectionsDownload", c->NumTcpConnectionsDownload);\r
+       PackAddInt(p, "UseEncrypt", c->UseEncrypt);\r
+       PackAddInt(p, "UseCompress", c->UseCompress);\r
+\r
+       PackAddBool(p, "IsBridgeMode", c->IsBridgeMode);\r
+       PackAddBool(p, "IsMonitorMode", c->IsMonitorMode);\r
+\r
+       PackAddInt64(p, "StartTime", c->StartTime);\r
+       PackAddInt64(p, "FirstConnectionEstablisiedTime", c->FirstConnectionEstablisiedTime);\r
+       PackAddInt64(p, "CurrentConnectionEstablishTime", c->CurrentConnectionEstablishTime);\r
+       PackAddInt64(p, "TotalSendSize", c->TotalSendSize);\r
+       PackAddInt64(p, "TotalRecvSize", c->TotalRecvSize);\r
+       PackAddInt64(p, "TotalSendSizeReal", c->TotalSendSizeReal);\r
+       PackAddInt64(p, "TotalRecvSizeReal", c->TotalRecvSizeReal);\r
+\r
+       PackAddInt(p, "VLanId", c->VLanId);\r
+\r
+       OutRpcPolicy(p, &c->Policy);\r
+\r
+       OutRpcTraffic(p, &c->Traffic);\r
+\r
+       if (c->ServerX != NULL)\r
+       {\r
+               b = XToBuf(c->ServerX, false);\r
+               PackAddBuf(p, "ServerX", b);\r
+               FreeBuf(b);\r
+       }\r
+\r
+       if (c->ClientX != NULL)\r
+       {\r
+               b = XToBuf(c->ClientX, false);\r
+               PackAddBuf(p, "ClientX", b);\r
+               FreeBuf(b);\r
+       }\r
+}\r
+\r
+void InRpcClientNotify(RPC_CLIENT_NOTIFY *n, PACK *p)\r
+{\r
+       // 引数チェック\r
+       if (n == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Zero(n, sizeof(RPC_CLIENT_NOTIFY));\r
+\r
+       n->NotifyCode = PackGetInt(p, "NotifyCode");\r
+}\r
+void OutRpcClientNotify(PACK *p, RPC_CLIENT_NOTIFY *n)\r
+{\r
+       // 引数チェック\r
+       if (n == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       PackAddInt(p, "NotifyCode", n->NotifyCode);\r
+}\r
+\r
+// 通知メイン\r
+void CiNotifyMain(CLIENT *c, SOCK *s)\r
+{\r
+       CANCEL *cancel;\r
+       // 引数チェック\r
+       if (c == NULL || s == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       // キャンセルを登録\r
+       cancel = NewCancel();\r
+       LockList(c->NotifyCancelList);\r
+       {\r
+               Add(c->NotifyCancelList, cancel);\r
+       }\r
+       UnlockList(c->NotifyCancelList);\r
+\r
+       // 待機\r
+       while (true)\r
+       {\r
+               char ch = '@';\r
+               SOCKSET set;\r
+               InitSockSet(&set);\r
+               AddSockSet(&set, s);\r
+               Select(&set, INFINITE, cancel, NULL);\r
+\r
+               if (c->Halt)\r
+               {\r
+                       // 強制終了\r
+                       break;\r
+               }\r
+\r
+               // 1 バイト送信\r
+               if (Send(s, &ch, 1, false) == 0)\r
+               {\r
+                       // 切断された\r
+                       break;\r
+               }\r
+       }\r
+\r
+       // 切断\r
+       Disconnect(s);\r
+\r
+       // キャンセルを登録解除\r
+       LockList(c->NotifyCancelList);\r
+       {\r
+               Delete(c->NotifyCancelList, cancel);\r
+       }\r
+       UnlockList(c->NotifyCancelList);\r
+\r
+       ReleaseCancel(cancel);\r
+}\r
+\r
+// RPC 受付コード\r
+void CiRpcAccepted(CLIENT *c, SOCK *s)\r
+{\r
+       UCHAR hashed_password[SHA1_SIZE];\r
+       UINT rpc_mode;\r
+       UINT retcode;\r
+       RPC *rpc;\r
+       // 引数チェック\r
+       if (c == NULL || s == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       // RPC モード受信\r
+       if (RecvAll(s, &rpc_mode, sizeof(UINT), false) == false)\r
+       {\r
+               return;\r
+       }\r
+\r
+       rpc_mode = Endian32(rpc_mode);\r
+\r
+       if (rpc_mode == CLIENT_RPC_MODE_NOTIFY)\r
+       {\r
+               // 通知モード\r
+               CiNotifyMain(c, s);\r
+               return;\r
+       }\r
+       else if (rpc_mode == CLIENT_RPC_MODE_SHORTCUT || rpc_mode == CLIENT_RPC_MODE_SHORTCUT_DISCONNECT)\r
+       {\r
+               // ショートカットキー受信\r
+               UCHAR key[SHA1_SIZE];\r
+               UINT err = ERR_NO_ERROR;\r
+               if (RecvAll(s, key, SHA1_SIZE, false))\r
+               {\r
+                       UINT i;\r
+                       wchar_t title[MAX_ACCOUNT_NAME_LEN + 1];\r
+                       bool ok = false;\r
+                       // 指定された接続設定に接続する\r
+                       LockList(c->AccountList);\r
+                       {\r
+                               for (i = 0;i < LIST_NUM(c->AccountList);i++)\r
+                               {\r
+                                       ACCOUNT *a = LIST_DATA(c->AccountList, i);\r
+                                       Lock(a->lock);\r
+                                       {\r
+                                               if (Cmp(a->ShortcutKey, key, SHA1_SIZE) == 0)\r
+                                               {\r
+                                                       ok = true;\r
+                                                       UniStrCpy(title, sizeof(title), a->ClientOption->AccountName);\r
+                                               }\r
+                                       }\r
+                                       Unlock(a->lock);\r
+                               }\r
+                       }\r
+                       UnlockList(c->AccountList);\r
+\r
+                       if (ok == false)\r
+                       {\r
+                               err = ERR_ACCOUNT_NOT_FOUND;\r
+                       }\r
+                       else\r
+                       {\r
+                               RPC_CLIENT_CONNECT t;\r
+                               Zero(&t, sizeof(t));\r
+                               UniStrCpy(t.AccountName, sizeof(t.AccountName), title);\r
+\r
+                               if (rpc_mode == CLIENT_RPC_MODE_SHORTCUT)\r
+                               {\r
+                                       // 接続\r
+                                       if (CtConnect(c, &t))\r
+                                       {\r
+                                               err = ERR_NO_ERROR;\r
+                                       }\r
+                                       else\r
+                                       {\r
+                                               err = c->Err;\r
+                                       }\r
+                               }\r
+                               else\r
+                               {\r
+                                       // 接続\r
+                                       if (CtDisconnect(c, &t))\r
+                                       {\r
+                                               err = ERR_NO_ERROR;\r
+                                       }\r
+                                       else\r
+                                       {\r
+                                               err = c->Err;\r
+                                       }\r
+                               }\r
+                       }\r
+\r
+                       err = Endian32(err);\r
+                       SendAll(s, &err, sizeof(UINT), false);\r
+                       RecvAll(s, &err, sizeof(UINT), false);\r
+               }\r
+               return;\r
+       }\r
+\r
+       // パスワード受信\r
+       if (RecvAll(s, hashed_password, SHA1_SIZE, false) == false)\r
+       {\r
+               return;\r
+       }\r
+\r
+       retcode = 0;\r
+\r
+       // パスワード比較\r
+       if (Cmp(hashed_password, c->EncryptedPassword, SHA1_SIZE) != 0)\r
+       {\r
+               retcode = 1;\r
+       }\r
+\r
+       if (c->PasswordRemoteOnly && s->RemoteIP.addr[0] == 127)\r
+       {\r
+               // リモートのみパスワードを要求するモードで、ローカルから接続された場合は\r
+               // パスワードを常に正しいと見なす\r
+               retcode = 0;\r
+       }\r
+\r
+       Lock(c->lock);\r
+       {\r
+               if (c->Config.AllowRemoteConfig == false)\r
+               {\r
+                       // リモート管理が禁止されている場合は\r
+                       // このコネクションが外部からのものであるかどうか識別する\r
+                       if (s->RemoteIP.addr[0] != 127)\r
+                       {\r
+                               retcode = 2;\r
+                       }\r
+               }\r
+       }\r
+       Unlock(c->lock);\r
+\r
+       retcode = Endian32(retcode);\r
+       // エラーコード送信\r
+       if (SendAll(s, &retcode, sizeof(UINT), false) == false)\r
+       {\r
+               return;\r
+       }\r
+\r
+\r
+\r
+       if (retcode != 0)\r
+       {\r
+               // エラーによる切断\r
+               return;\r
+       }\r
+\r
+       // RPC サーバー作成\r
+       rpc = StartRpcServer(s, CiRpcDispatch, c);\r
+\r
+       // RPC サーバー動作\r
+       RpcServer(rpc);\r
+\r
+       // RPC サーバーの解放\r
+       EndRpc(rpc);\r
+}\r
+\r
+// RPC 受付スレッド\r
+void CiRpcAcceptThread(THREAD *thread, void *param)\r
+{\r
+       CLIENT_RPC_CONNECTION *conn;\r
+       CLIENT *c;\r
+       SOCK *s;\r
+       // 引数チェック\r
+       if (thread == NULL || param == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       conn = (CLIENT_RPC_CONNECTION *)param;\r
+       s = conn->Sock;\r
+       c = conn->Client;\r
+       AddRef(s->ref);\r
+\r
+       // RPC コネクションリストに追加\r
+       LockList(c->RpcConnectionList);\r
+       {\r
+               Add(c->RpcConnectionList, conn);\r
+       }\r
+       UnlockList(c->RpcConnectionList);\r
+\r
+       NoticeThreadInit(thread);\r
+\r
+       // メイン処理\r
+       CiRpcAccepted(c, s);\r
+\r
+       // コネクションリストから解放\r
+       LockList(c->RpcConnectionList);\r
+       {\r
+               Delete(c->RpcConnectionList, conn);\r
+       }\r
+       UnlockList(c->RpcConnectionList);\r
+\r
+       ReleaseSock(conn->Sock);\r
+       ReleaseThread(conn->Thread);\r
+       Free(conn);\r
+\r
+       Disconnect(s);\r
+       ReleaseSock(s);\r
+}\r
+\r
+// RPC サーバースレッド\r
+void CiRpcServerThread(THREAD *thread, void *param)\r
+{\r
+       CLIENT *c;\r
+       SOCK *listener;\r
+       UINT i;\r
+       LIST *thread_list;\r
+       // 引数チェック\r
+       if (thread == NULL || param == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       c = (CLIENT *)param;\r
+\r
+       // RPC コネクションリスト\r
+       c->RpcConnectionList = NewList(NULL);\r
+\r
+       // ポートを開く\r
+       listener = NULL;\r
+       for (i = CLIENT_CONFIG_PORT;i < (CLIENT_CONFIG_PORT + 5);i++)\r
+       {\r
+               listener = Listen(i);\r
+               if (listener != NULL)\r
+               {\r
+                       break;\r
+               }\r
+       }\r
+\r
+       if (listener == NULL)\r
+       {\r
+               // エラー\r
+               Alert("SoftEther UT-VPN Client RPC Port Open Failed.", CEDAR_CLIENT_STR);\r
+               return;\r
+       }\r
+\r
+       c->RpcListener = listener;\r
+       AddRef(listener->ref);\r
+\r
+       NoticeThreadInit(thread);\r
+\r
+       while (true)\r
+       {\r
+               // クライアント接続を待機\r
+               CLIENT_RPC_CONNECTION *conn;\r
+               SOCK *s = Accept(listener);\r
+               if (s == NULL)\r
+               {\r
+                       // 停止\r
+                       break;\r
+               }\r
+\r
+               // クライアント処理用スレッドを作成する\r
+               conn = ZeroMalloc(sizeof(CLIENT_RPC_CONNECTION));\r
+               conn->Client = c;\r
+               conn->Sock = s;\r
+               AddRef(s->ref);\r
+\r
+               conn->Thread = NewThread(CiRpcAcceptThread, (void *)conn);\r
+               WaitThreadInit(conn->Thread);\r
+\r
+               ReleaseSock(s);\r
+       }\r
+\r
+       // リスナーを解放\r
+       ReleaseSock(listener);\r
+\r
+       thread_list = NewListFast(NULL);\r
+\r
+       // すべての通知イベントを起動する\r
+       LockList(c->NotifyCancelList);\r
+       {\r
+               UINT i;\r
+               for (i = 0;i < LIST_NUM(c->NotifyCancelList);i++)\r
+               {\r
+                       CANCEL *cancel = LIST_DATA(c->NotifyCancelList, i);\r
+                       Cancel(cancel);\r
+               }\r
+       }\r
+       UnlockList(c->NotifyCancelList);\r
+\r
+       // まだ接続しているすべてのコネクションを切断する\r
+       LockList(c->RpcConnectionList);\r
+       {\r
+               for (i = 0;i < LIST_NUM(c->RpcConnectionList);i++)\r
+               {\r
+                       CLIENT_RPC_CONNECTION *cc = LIST_DATA(c->RpcConnectionList, i);\r
+                       AddRef(cc->Thread->ref);\r
+                       Add(thread_list, cc->Thread);\r
+                       Disconnect(cc->Sock);\r
+               }\r
+       }\r
+       UnlockList(c->RpcConnectionList);\r
+\r
+       for (i = 0;i < LIST_NUM(thread_list);i++)\r
+       {\r
+               THREAD *t = LIST_DATA(thread_list, i);\r
+               WaitThread(t, INFINITE);\r
+               ReleaseThread(t);\r
+       }\r
+\r
+       ReleaseList(c->RpcConnectionList);\r
+       ReleaseList(thread_list);\r
+}\r
+\r
+// Keep を開始\r
+void CiInitKeep(CLIENT *c)\r
+{\r
+       // 引数チェック\r
+       if (c == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       c->Keep = StartKeep();\r
+\r
+       // 設定の適用\r
+       if (c->Config.UseKeepConnect)\r
+       {\r
+               KEEP *k = c->Keep;\r
+               Lock(k->lock);\r
+               {\r
+                       StrCpy(k->ServerName, sizeof(k->ServerName), c->Config.KeepConnectHost);\r
+                       k->ServerPort = c->Config.KeepConnectPort;\r
+                       k->Interval = c->Config.KeepConnectInterval * 1000;\r
+                       k->UdpMode = (c->Config.KeepConnectProtocol == CONNECTION_UDP) ? true : false;\r
+                       k->Enable = true;\r
+               }\r
+               Unlock(k->lock);\r
+       }\r
+}\r
+\r
+// Keep を停止\r
+void CiFreeKeep(CLIENT *c)\r
+{\r
+       // 引数チェック\r
+       if (c == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       StopKeep(c->Keep);\r
+       c->Keep = NULL;\r
+}\r
+\r
+// RPC を開始\r
+void CiStartRpcServer(CLIENT *c)\r
+{\r
+       // 引数チェック\r
+       if (c == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       c->RpcThread = NewThread(CiRpcServerThread, (void *)c);\r
+       WaitThreadInit(c->RpcThread);\r
+}\r
+\r
+// RPC を終了\r
+void CiStopRpcServer(CLIENT *c)\r
+{\r
+       // 引数チェック\r
+       if (c == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Disconnect(c->RpcListener);\r
+       ReleaseSock(c->RpcListener);\r
+\r
+       WaitThread(c->RpcThread, INFINITE);\r
+       ReleaseThread(c->RpcThread);\r
+}\r
+\r
+// 次の通知を待機する\r
+bool CcWaitNotify(NOTIFY_CLIENT *n)\r
+{\r
+       UCHAR c;\r
+       // 引数チェック\r
+       if (n == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       // 1 文字受信する\r
+       if (RecvAll(n->Sock, &c, 1, false) == false)\r
+       {\r
+               // 切断された\r
+               return false;\r
+       }\r
+\r
+       return true;\r
+}\r
+\r
+// 通知クライアントとして接続する\r
+NOTIFY_CLIENT *CcConnectNotify(REMOTE_CLIENT *rc)\r
+{\r
+       NOTIFY_CLIENT *n;\r
+       SOCK *s;\r
+       char tmp[MAX_SIZE];\r
+       bool rpc_mode = false;\r
+       UINT port;\r
+       // 引数チェック\r
+       if (rc == NULL || rc->Rpc == NULL || rc->Rpc->Sock == NULL)\r
+       {\r
+               return NULL;\r
+       }\r
+\r
+       // 接続\r
+       IPToStr(tmp, sizeof(tmp), &rc->Rpc->Sock->RemoteIP);\r
+       port = rc->Rpc->Sock->RemotePort;\r
+\r
+       s = Connect(tmp, port);\r
+       if (s == NULL)\r
+       {\r
+               return NULL;\r
+       }\r
+\r
+       rpc_mode = Endian32(rpc_mode);\r
+       if (SendAll(s, &rpc_mode, sizeof(rpc_mode), false) == false)\r
+       {\r
+               ReleaseSock(s);\r
+               return NULL;\r
+       }\r
+\r
+       n = ZeroMalloc(sizeof(NOTIFY_CLIENT));\r
+       n->Sock = s;\r
+\r
+       return n;\r
+}\r
+\r
+// 通知クライアントを停止する\r
+void CcStopNotify(NOTIFY_CLIENT *n)\r
+{\r
+       // 引数チェック\r
+       if (n == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Disconnect(n->Sock);\r
+}\r
+\r
+// 通知クライアントを削除する\r
+void CcDisconnectNotify(NOTIFY_CLIENT *n)\r
+{\r
+       // 引数チェック\r
+       if (n == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       // 切断\r
+       Disconnect(n->Sock);\r
+       ReleaseSock(n->Sock);\r
+\r
+       // メモリ解放\r
+       Free(n);\r
+}\r
+\r
+// リモート接続を切断する\r
+void CcDisconnectRpc(REMOTE_CLIENT *rc)\r
+{\r
+       // 引数チェック\r
+       if (rc == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       RpcFree(rc->Rpc);\r
+       Free(rc);\r
+}\r
+\r
+// クライアントに接続しショートカット接続設定を起動する\r
+UINT CcShortcut(UCHAR *key)\r
+{\r
+       UINT ret;\r
+       // 引数チェック\r
+       if (key == NULL)\r
+       {\r
+               return ERR_INVALID_PARAMETER;\r
+       }\r
+\r
+       CcConnectRpcEx("localhost", NULL, NULL, NULL, key, &ret, false, 0);\r
+\r
+       return ret;\r
+}\r
+\r
+// 接続中のショートカット接続を切断する\r
+UINT CcShortcutDisconnect(UCHAR *key)\r
+{\r
+       UINT ret;\r
+       // 引数チェック\r
+       if (key == NULL)\r
+       {\r
+               return ERR_INVALID_PARAMETER;\r
+       }\r
+\r
+       CcConnectRpcEx("localhost", NULL, NULL, NULL, key, &ret, true, 0);\r
+\r
+       return ret;\r
+}\r
+\r
+// クライアントにリモート接続する\r
+REMOTE_CLIENT *CcConnectRpc(char *server_name, char *password, bool *bad_pass, bool *no_remote, UINT wait_retry)\r
+{\r
+       return CcConnectRpcEx(server_name, password, bad_pass, no_remote, NULL, NULL, false, wait_retry);\r
+}\r
+REMOTE_CLIENT *CcConnectRpcEx(char *server_name, char *password, bool *bad_pass, bool *no_remote, UCHAR *key, UINT *key_error_code, bool shortcut_disconnect, UINT wait_retry)\r
+{\r
+       SOCK *s;\r
+       UINT i;\r
+       UINT retcode;\r
+       UINT rpc_mode = CLIENT_RPC_MODE_MANAGEMENT;\r
+       RPC *rpc;\r
+       REMOTE_CLIENT *ret;\r
+       UCHAR hash_password[SHA1_SIZE];\r
+       UINT port_start;\r
+       UINT64 try_started = 0;\r
+       bool ok;\r
+       // 引数チェック\r
+       if (server_name == NULL)\r
+       {\r
+               return NULL;\r
+       }\r
+       if (password == NULL)\r
+       {\r
+               password = "";\r
+       }\r
+\r
+       if (key_error_code != NULL)\r
+       {\r
+               *key_error_code = ERR_NO_ERROR;\r
+       }\r
+\r
+       if (bad_pass != NULL)\r
+       {\r
+               *bad_pass = false;\r
+       }\r
+\r
+       if (no_remote != NULL)\r
+       {\r
+               *no_remote = false;\r
+       }\r
+\r
+       port_start = CLIENT_CONFIG_PORT - 1;\r
+\r
+RETRY:\r
+       port_start++;\r
+\r
+       if (port_start >= (CLIENT_CONFIG_PORT + 5))\r
+       {\r
+               return NULL;\r
+       }\r
+\r
+       ok = false;\r
+\r
+       while (true)\r
+       {\r
+               for (i = port_start;i < (CLIENT_CONFIG_PORT + 5);i++)\r
+               {\r
+                       if (CheckTCPPort(server_name, i))\r
+                       {\r
+                               ok = true;\r
+                               break;\r
+                       }\r
+               }\r
+\r
+               if (ok)\r
+               {\r
+                       break;\r
+               }\r
+\r
+               if (wait_retry == 0)\r
+               {\r
+                       break;\r
+               }\r
+\r
+               if (try_started == 0)\r
+               {\r
+                       try_started = Tick64();\r
+               }\r
+\r
+               if ((try_started + (UINT64)wait_retry) <= Tick64())\r
+               {\r
+                       break;\r
+               }\r
+       }\r
+\r
+       if (ok == false)\r
+       {\r
+               if (key_error_code)\r
+               {\r
+                       *key_error_code = ERR_CONNECT_FAILED;\r
+               }\r
+               return NULL;\r
+       }\r
+\r
+       port_start = i;\r
+\r
+       s = Connect(server_name, i);\r
+       if (s == NULL)\r
+       {\r
+               if (key_error_code)\r
+               {\r
+                       *key_error_code = ERR_CONNECT_FAILED;\r
+               }\r
+               goto RETRY;\r
+       }\r
+\r
+       Hash(hash_password, password, StrLen(password), true);\r
+\r
+       if (key != NULL)\r
+       {\r
+               if (shortcut_disconnect == false)\r
+               {\r
+                       rpc_mode = CLIENT_RPC_MODE_SHORTCUT;\r
+               }\r
+               else\r
+               {\r
+                       rpc_mode = CLIENT_RPC_MODE_SHORTCUT_DISCONNECT;\r
+               }\r
+       }\r
+\r
+       rpc_mode = Endian32(rpc_mode);\r
+       SendAdd(s, &rpc_mode, sizeof(UINT));\r
+\r
+       if (key != NULL)\r
+       {\r
+               SendAdd(s, key, SHA1_SIZE);\r
+       }\r
+       else\r
+       {\r
+               SendAdd(s, hash_password, SHA1_SIZE);\r
+       }\r
+\r
+       if (SendNow(s, false) == false)\r
+       {\r
+               ReleaseSock(s);\r
+               goto RETRY;\r
+       }\r
+\r
+       if (RecvAll(s, &retcode, sizeof(UINT), false) == false)\r
+       {\r
+               ReleaseSock(s);\r
+               goto RETRY;\r
+       }\r
+\r
+       retcode = Endian32(retcode);\r
+\r
+       if (retcode >= 1024)\r
+       {\r
+               goto RETRY;\r
+       }\r
+\r
+       if (key != NULL)\r
+       {\r
+               if (key_error_code)\r
+               {\r
+                       *key_error_code = retcode;\r
+               }\r
+               SendAll(s, &retcode, sizeof(UINT), false);\r
+               ReleaseSock(s);\r
+               return NULL;\r
+       }\r
+\r
+       switch (retcode)\r
+       {\r
+       case 1:\r
+               if (bad_pass != NULL)\r
+               {\r
+                       *bad_pass = true;\r
+               }\r
+               break;\r
+       case 2:\r
+               if (no_remote != NULL)\r
+               {\r
+                       *no_remote = true;\r
+               }\r
+               break;\r
+       }\r
+\r
+       if (retcode != 0)\r
+       {\r
+               ReleaseSock(s);\r
+               return NULL;\r
+       }\r
+\r
+       rpc = StartRpcClient(s, NULL);\r
+\r
+       ReleaseSock(s);\r
+\r
+       ret = ZeroMalloc(sizeof(REMOTE_CLIENT));\r
+       ret->Rpc = rpc;\r
+       rpc->Param = ret;\r
+\r
+       if (ret != NULL)\r
+       {\r
+               RPC_CLIENT_VERSION t;\r
+               Zero(&t, sizeof(t));\r
+               CcGetClientVersion(ret, &t);\r
+               ret->OsType = t.OsType;\r
+               ret->Unix = OS_IS_UNIX(ret->OsType);\r
+               ret->Win9x = OS_IS_WINDOWS_9X(ret->OsType);\r
+       }\r
+\r
+       return ret;\r
+}\r
+\r
+// セッションから RPC_CLIENT_GET_CONNECTION_STATUS を取得\r
+void CiGetSessionStatus(RPC_CLIENT_GET_CONNECTION_STATUS *st, SESSION *s)\r
+{\r
+       // 引数チェック\r
+       if (st == NULL || s == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Lock(s->lock);\r
+       {\r
+               // 動作フラグ\r
+               st->Active = true;\r
+\r
+               // セッションステータス\r
+               st->SessionStatus = s->ClientStatus;\r
+\r
+               // アカウント名\r
+               UniStrCpy(st->AccountName, sizeof(st->AccountName), s->ClientOption->AccountName);\r
+\r
+               if (s->ClientStatus == CLIENT_STATUS_ESTABLISHED && s->Connection != NULL)\r
+               {\r
+                       Lock(s->Connection->lock);\r
+                       {\r
+                               // 接続済みフラグ\r
+                               st->Connected = true;\r
+                               // 製品名\r
+                               StrCpy(st->ServerProductName, sizeof(st->ServerProductName), s->Connection->ServerStr);\r
+                               // バージョン\r
+                               st->ServerProductVer = s->Connection->ServerVer;\r
+                               // ビルド番号\r
+                               st->ServerProductBuild = s->Connection->ServerBuild;\r
+                               // サーバー証明書\r
+                               st->ServerX = CloneX(s->Connection->ServerX);\r
+                               // クライアント証明書\r
+                               st->ClientX = CloneX(s->Connection->ClientX);\r
+                               // このコネクションの接続完了時刻\r
+                               st->CurrentConnectionEstablishTime = TickToTime(s->CurrentConnectionEstablishTime);\r
+                               // 最大の TCP コネクション数\r
+                               st->MaxTcpConnections = s->MaxConnection;\r
+                               // ハーフコネクション\r
+                               st->HalfConnection = s->HalfConnection;\r
+                               // VLAN\r
+                               st->VLanId = s->VLanId;\r
+                               // VoIP / QoS\r
+                               st->QoS = s->QoS;\r
+                               if (s->Connection->Protocol == CONNECTION_TCP)\r
+                               {\r
+                                       UINT i;\r
+                                       // 現在の TCP コネクション数\r
+                                       LockList(s->Connection->Tcp->TcpSockList);\r
+                                       {\r
+                                               st->NumTcpConnections = LIST_NUM(s->Connection->Tcp->TcpSockList);\r
+                                               if (st->HalfConnection)\r
+                                               {\r
+                                                       for (i = 0;i < st->NumTcpConnections;i++)\r
+                                                       {\r
+                                                               TCPSOCK *ts = LIST_DATA(s->Connection->Tcp->TcpSockList, i);\r
+                                                               if (ts->Direction & TCP_SERVER_TO_CLIENT)\r
+                                                               {\r
+                                                                       st->NumTcpConnectionsDownload++;\r
+                                                               }\r
+                                                               else\r
+                                                               {\r
+                                                                       st->NumTcpConnectionsUpload++;\r
+                                                               }\r
+                                                       }\r
+                                               }\r
+                                       }\r
+                                       UnlockList(s->Connection->Tcp->TcpSockList);\r
+                               }\r
+                               // 暗号化の使用\r
+                               st->UseEncrypt = s->UseEncrypt;\r
+                               if (st->UseEncrypt)\r
+                               {\r
+                                       StrCpy(st->CipherName, sizeof(st->CipherName), s->Connection->CipherName);\r
+                               }\r
+                               // 圧縮の使用\r
+                               st->UseCompress = s->UseCompress;\r
+                               // セッションキー\r
+                               Copy(st->SessionKey, s->SessionKey, SHA1_SIZE);\r
+                               // ポリシー\r
+                               Copy(&st->Policy, s->Policy, sizeof(POLICY));\r
+                               // データサイズ\r
+                               if (s->ServerMode == false)\r
+                               {\r
+                                       st->TotalSendSize = s->TotalSendSize;\r
+                                       st->TotalRecvSize = s->TotalRecvSize;\r
+                                       st->TotalRecvSizeReal = s->TotalRecvSizeReal;\r
+                                       st->TotalSendSizeReal = s->TotalSendSizeReal;\r
+                               }\r
+                               else\r
+                               {\r
+                                       st->TotalSendSize = s->TotalRecvSize;\r
+                                       st->TotalRecvSize = s->TotalSendSize;\r
+                                       st->TotalRecvSizeReal = s->TotalSendSizeReal;\r
+                                       st->TotalSendSizeReal = s->TotalRecvSizeReal;\r
+                               }\r
+                               // セッション名\r
+                               StrCpy(st->SessionName, sizeof(st->SessionName), s->Name);\r
+                               // コネクション名\r
+                               StrCpy(st->ConnectionName, sizeof(st->ConnectionName), s->Connection->Name);\r
+                               // サーバー名\r
+                               StrCpy(st->ServerName, sizeof(st->ServerName), s->Connection->ServerName);\r
+                               // ポート番号\r
+                               st->ServerPort = s->Connection->ServerPort;\r
+                               // トラフィックデータ\r
+                               Lock(s->TrafficLock);\r
+                               {\r
+                                       Copy(&st->Traffic, s->Traffic, sizeof(TRAFFIC));\r
+                               }\r
+                               Unlock(s->TrafficLock);\r
+\r
+                               st->IsBridgeMode = s->IsBridgeMode;\r
+                               st->IsMonitorMode = s->IsMonitorMode;\r
+                       }\r
+                       Unlock(s->Connection->lock);\r
+               }\r
+               // 接続開始時刻\r
+               st->StartTime = TickToTime(s->CreatedTime);\r
+               // 最初のコネクションの接続完了時刻\r
+               st->FirstConnectionEstablisiedTime = TickToTime(s->FirstConnectionEstablisiedTime);\r
+               // これまでに確立したコネクション数\r
+               st->NumConnectionsEatablished = s->NumConnectionsEatablished;\r
+       }\r
+       Unlock(s->lock);\r
+}\r
+\r
+// 接続ステータスの取得\r
+bool CtGetAccountStatus(CLIENT *c, RPC_CLIENT_GET_CONNECTION_STATUS *st)\r
+{\r
+       // 引数チェック\r
+       if (c == NULL || st == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       LockList(c->AccountList);\r
+       {\r
+               ACCOUNT t, *r;\r
+\r
+               // アカウントを検索\r
+               t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));\r
+               UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), st->AccountName);\r
+\r
+               r = Search(c->AccountList, &t);\r
+               if (r == NULL)\r
+               {\r
+                       // 指定したアカウントは見つからない\r
+                       UnlockList(c->AccountList);\r
+\r
+                       Free(t.ClientOption);\r
+                       CiSetError(c, ERR_ACCOUNT_NOT_FOUND);\r
+                       return false;\r
+               }\r
+\r
+               Free(t.ClientOption);\r
+\r
+               Lock(r->lock);\r
+               {\r
+                       Zero(st, sizeof(RPC_CLIENT_GET_CONNECTION_STATUS));\r
+                       if (r->ClientSession != NULL)\r
+                       {\r
+                               SESSION *s = r->ClientSession;\r
+                               CiGetSessionStatus(st, s);\r
+                       }\r
+               }\r
+               Unlock(r->lock);\r
+       }\r
+       UnlockList(c->AccountList);\r
+\r
+       return true;\r
+}\r
+\r
+// 接続ステータスの解放\r
+void CiFreeClientGetConnectionStatus(RPC_CLIENT_GET_CONNECTION_STATUS *st)\r
+{\r
+       // 引数チェック\r
+       if (st == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       if (st->ServerX != NULL)\r
+       {\r
+               FreeX(st->ServerX);\r
+       }\r
+\r
+       if (st->ClientX != NULL)\r
+       {\r
+               FreeX(st->ClientX);\r
+       }\r
+}\r
+\r
+// サーバー証明書の確認プロシージャ\r
+bool CiCheckCertProc(SESSION *s, CONNECTION *c, X *server_x, bool *expired)\r
+{\r
+#ifdef OS_WIN32\r
+       ACCOUNT *a;\r
+       X *old_x = NULL;\r
+       UI_CHECKCERT dlg;\r
+       // 引数チェック\r
+       if (s == NULL || c == NULL || server_x == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       if (expired != NULL)\r
+       {\r
+               *expired = false;\r
+       }\r
+\r
+       Zero(&dlg, sizeof(dlg));\r
+\r
+       a = s->Account;\r
+       if (a == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       Lock(a->lock);\r
+       {\r
+               if (a->CheckServerCert == false)\r
+               {\r
+                       // サーバー証明書を検証しない\r
+                       Unlock(a->lock);\r
+                       return true;\r
+               }\r
+\r
+               if (a->ServerCert != NULL)\r
+               {\r
+                       old_x = CloneX(a->ServerCert);\r
+               }\r
+       }\r
+       Unlock(a->lock);\r
+\r
+       if (CheckXDateNow(server_x) == false)\r
+       {\r
+               // 有効期限が切れている\r
+               if (old_x != NULL)\r
+               {\r
+                       FreeX(old_x);\r
+               }\r
+\r
+               if (expired != NULL)\r
+               {\r
+                       *expired = true;\r
+               }\r
+\r
+               return false;\r
+       }\r
+\r
+       if (old_x != NULL)\r
+       {\r
+               if (CompareX(old_x, server_x))\r
+               {\r
+                       // すでに登録されている証明書と完全一致した\r
+                       if (old_x != NULL)\r
+                       {\r
+                               FreeX(old_x);\r
+                       }\r
+                       return true;\r
+               }\r
+               else\r
+               {\r
+                       dlg.DiffWarning = true;\r
+               }\r
+       }\r
+\r
+       // この証明書は信頼できないのでダイアログボックスを出して確認する\r
+       UniStrCpy(dlg.AccountName, sizeof(dlg.AccountName), a->ClientOption->AccountName);\r
+       StrCpy(dlg.ServerName, sizeof(dlg.ServerName), a->ClientOption->Hostname);\r
+       dlg.x = server_x;\r
+       dlg.old_x = old_x;\r
+       \r
+       dlg.Session = s;\r
+       AddRef(s->ref);\r
+\r
+       CncCheckCert(s, &dlg);\r
+\r
+       ReleaseSession(s);\r
+\r
+       if (old_x != NULL)\r
+       {\r
+               FreeX(old_x);\r
+       }\r
+\r
+       if (dlg.Ok && dlg.SaveServerCert)\r
+       {\r
+               // このサーバー証明書を保存し次回から信頼する\r
+               Lock(a->lock);\r
+               {\r
+                       if (a->ServerCert != NULL)\r
+                       {\r
+                               FreeX(a->ServerCert);\r
+                       }\r
+\r
+                       a->ServerCert = CloneX(server_x);\r
+               }\r
+               Unlock(a->lock);\r
+               CiSaveConfigurationFile(s->Cedar->Client);\r
+       }\r
+\r
+       return dlg.Ok;\r
+#else  // OS_WIN32\r
+       ACCOUNT *a;\r
+       X *old_x = NULL;\r
+       // 引数チェック\r
+       if (s == NULL || c == NULL || server_x == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       if (expired != NULL)\r
+       {\r
+               *expired = false;\r
+       }\r
+\r
+       a = s->Account;\r
+       if (a == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       Lock(a->lock);\r
+       {\r
+               if (a->CheckServerCert == false)\r
+               {\r
+                       // サーバー証明書を検証しない\r
+                       Unlock(a->lock);\r
+                       return true;\r
+               }\r
+\r
+               if (a->ServerCert != NULL)\r
+               {\r
+                       old_x = CloneX(a->ServerCert);\r
+               }\r
+       }\r
+       Unlock(a->lock);\r
+\r
+       if (CheckXDateNow(server_x) == false)\r
+       {\r
+               // 有効期限が切れている\r
+               if (old_x != NULL)\r
+               {\r
+                       FreeX(old_x);\r
+               }\r
+\r
+               if (expired != NULL)\r
+               {\r
+                       *expired = true;\r
+               }\r
+\r
+               return false;\r
+       }\r
+\r
+       if (old_x != NULL)\r
+       {\r
+               if (CompareX(old_x, server_x))\r
+               {\r
+                       // すでに登録されている証明書と完全一致した\r
+                       if (old_x != NULL)\r
+                       {\r
+                               FreeX(old_x);\r
+                       }\r
+                       return true;\r
+               }\r
+               else\r
+               {\r
+                       // 不一致\r
+                       if (old_x != NULL)\r
+                       {\r
+                               FreeX(old_x);\r
+                       }\r
+                       return false;\r
+               }\r
+       }\r
+\r
+       if (old_x != NULL)\r
+       {\r
+               FreeX(old_x);\r
+       }\r
+\r
+       return false;\r
+#endif // OS_WIN32\r
+}\r
+\r
+// セキュアデバイスを使用した署名プロシージャ\r
+bool CiSecureSignProc(SESSION *s, CONNECTION *c, SECURE_SIGN *sign)\r
+{\r
+       // Win32 の場合は UI を使用することができる\r
+       return CncSecureSignDlg(sign);\r
+}\r
+\r
+#ifdef OS_WIN32\r
+// 署名プロシージャ (Win32 用)\r
+bool Win32CiSecureSign(SECURE_SIGN *sign)\r
+{\r
+       bool ret = false;\r
+       BUF *random;\r
+       // 引数チェック\r
+       if (sign == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       random = NewBuf();\r
+       WriteBuf(random, sign->Random, SHA1_SIZE);\r
+\r
+       // バッチ処理\r
+       {\r
+               WINUI_SECURE_BATCH batch[] =\r
+               {\r
+                       {WINUI_SECURE_READ_CERT, sign->SecurePublicCertName, true, NULL, NULL, NULL, NULL, NULL, NULL},\r
+                       {WINUI_SECURE_SIGN_WITH_KEY, sign->SecurePrivateKeyName, true, random, NULL, NULL, NULL, NULL, NULL}\r
+               };\r
+\r
+               if (SecureDeviceWindow(NULL, batch, sizeof(batch) / sizeof(batch[0]),\r
+                       sign->UseSecureDeviceId, sign->BitmapId) == false)\r
+               {\r
+                       // 失敗\r
+                       if (batch[0].OutputX != 0)\r
+                       {\r
+                               FreeX(batch[0].OutputX);\r
+                       }\r
+                       ret = false;\r
+               }\r
+               else\r
+               {\r
+                       // 成功\r
+                       ret = true;\r
+                       sign->ClientCert = batch[0].OutputX;\r
+                       Copy(sign->Signature, batch[1].OutputSign, 128);\r
+               }\r
+       }\r
+\r
+       FreeBuf(random);\r
+\r
+       return ret;\r
+}\r
+#endif // OS_WIN32\r
+\r
+// 切断\r
+bool CtDisconnect(CLIENT *c, RPC_CLIENT_CONNECT *connect)\r
+{\r
+       bool ret = false;\r
+       ACCOUNT t, *r;\r
+       SESSION *s = NULL;\r
+       // 引数チェック\r
+       if (c == NULL || connect == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       LockList(c->AccountList);\r
+       {\r
+\r
+               // アカウントを検索\r
+               t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));\r
+               UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), connect->AccountName);\r
+\r
+               r = Search(c->AccountList, &t);\r
+               if (r == NULL)\r
+               {\r
+                       // 指定したアカウントは見つからない\r
+                       UnlockList(c->AccountList);\r
+\r
+                       Free(t.ClientOption);\r
+                       CiSetError(c, ERR_ACCOUNT_NOT_FOUND);\r
+                       return false;\r
+               }\r
+\r
+               Free(t.ClientOption);\r
+\r
+               Lock(r->lock);\r
+               {\r
+                       if (r->ClientSession == NULL)\r
+                       {\r
+                               // 接続していない\r
+                               CiSetError(c, ERR_ACCOUNT_INACTIVE);\r
+                       }\r
+                       else\r
+                       {\r
+                               s = r->ClientSession;\r
+                               AddRef(s->ref);\r
+                               // 切断完了\r
+                               r->ClientSession = NULL;\r
+                               ret = true;\r
+                       }\r
+               }\r
+               Unlock(r->lock);\r
+       }\r
+       UnlockList(c->AccountList);\r
+\r
+       if (s != NULL)\r
+       {\r
+               // 接続を切断 (切断完了まで待機)\r
+               CLog(c, "LC_DISCONNECT", connect->AccountName);\r
+               StopSession(s);\r
+               ReleaseSession(s);\r
+       }\r
+\r
+       if (ret != false)\r
+       {\r
+               CiNotify(c);\r
+       }\r
+\r
+       return ret;\r
+}\r
+\r
+// 接続\r
+bool CtConnect(CLIENT *c, RPC_CLIENT_CONNECT *connect)\r
+{\r
+       bool ret = false;\r
+       RPC_CLIENT_ENUM_VLAN t;\r
+       // 引数チェック\r
+       if (c == NULL || connect == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       Lock(c->lockForConnect);\r
+       {\r
+               Zero(&t, sizeof(t));\r
+               if (CtEnumVLan(c, &t))\r
+               {\r
+                       if (t.NumItem == 0)\r
+                       {\r
+                               // システムに仮想 LAN カードが 1 枚も無い\r
+                               if (OS_IS_WINDOWS_NT(GetOsInfo()->OsType) || OS_IS_UNIX(GetOsInfo()->OsType))\r
+                               {\r
+                                       // Windows NT 系または Linux 系の場合のみ、自動的に "VPN" という名前の\r
+                                       // 新しい仮想 LAN カードを作成する\r
+                                       RPC_CLIENT_CREATE_VLAN t;\r
+\r
+                                       Zero(&t, sizeof(t));\r
+                                       StrCpy(t.DeviceName, sizeof(t.DeviceName), "VPN");\r
+                                       CtCreateVLan(c,  &t);\r
+                               }\r
+                       }\r
+\r
+                       CiFreeClientEnumVLan(&t);\r
+               }\r
+       }\r
+       Unlock(c->lockForConnect);\r
+\r
+       CiNormalizeAccountVLan(c);\r
+\r
+       LockList(c->AccountList);\r
+       {\r
+               ACCOUNT t, *r;\r
+               bool unix_disabled = false;\r
+\r
+               // アカウントを検索\r
+               t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));\r
+               UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), connect->AccountName);\r
+\r
+               r = Search(c->AccountList, &t);\r
+               if (r == NULL)\r
+               {\r
+                       // 指定したアカウントは見つからない\r
+                       UnlockList(c->AccountList);\r
+\r
+                       Free(t.ClientOption);\r
+                       CiSetError(c, ERR_ACCOUNT_NOT_FOUND);\r
+                       return false;\r
+               }\r
+\r
+               Free(t.ClientOption);\r
+\r
+#ifndef        OS_WIN32\r
+               // 仮想 LAN カードを検索する\r
+               LockList(c->UnixVLanList);\r
+               {\r
+                       UNIX_VLAN *v, t;\r
+\r
+                       Zero(&t, sizeof(t));\r
+                       StrCpy(t.Name, sizeof(t.Name), r->ClientOption->DeviceName);\r
+\r
+                       v = Search(c->UnixVLanList, &t);\r
+                       if (v == NULL)\r
+                       {\r
+                               UnlockList(c->UnixVLanList);\r
+                               CiSetError(c, ERR_OBJECT_NOT_FOUND);\r
+                               return false;\r
+                       }\r
+\r
+                       unix_disabled = v->Enabled ? false : true;\r
+               }\r
+               UnlockList(c->UnixVLanList);\r
+#endif // OS_WIN32\r
+\r
+               Lock(r->lock);\r
+               {\r
+                       bool already_used = false;\r
+                       UINT i;\r
+\r
+                       if (r->ClientSession != NULL)\r
+                       {\r
+                               // すでに接続中\r
+                               CiSetError(c, ERR_ACCOUNT_ACTIVE);\r
+                       }\r
+                       else if (r->ClientAuth->AuthType == CLIENT_AUTHTYPE_SECURE &&\r
+                               client->UseSecureDeviceId == 0)\r
+                       {\r
+                               // セキュアデバイスが指定されていない\r
+                               CiSetError(c, ERR_NO_SECURE_DEVICE_SPECIFIED);\r
+                       }\r
+#ifdef OS_WIN32\r
+                       else if (MsIsVLanExists(VLAN_ADAPTER_NAME_TAG, r->ClientOption->DeviceName) == false)\r
+                       {\r
+                               // 仮想 LAN カードが見つからない\r
+                               CiSetError(c, ERR_VLAN_FOR_ACCOUNT_NOT_FOUND);\r
+                               CiNotify(c);\r
+                       }\r
+                       else if (MsIsVLanEnabled(r->ClientOption->DeviceName) == false)\r
+                       {\r
+                               // 仮想 LAN カードは無効化されている\r
+                               CiSetError(c, ERR_VLAN_FOR_ACCOUNT_DISABLED);\r
+                               CiNotify(c);\r
+                       }\r
+#else  // OS_WIN32\r
+                       else if (unix_disabled)\r
+                       {\r
+                               // 仮想 LAN カードは無効化されている\r
+                               CiSetError(c, ERR_VLAN_FOR_ACCOUNT_DISABLED);\r
+                               CiNotify(c);\r
+                       }\r
+#endif // OS_WIN32\r
+                       else\r
+                       {\r
+                               // 仮想 LAN カードがすでに別のアカウントで使用されているかどうか調べる\r
+                               for (i = 0;i < LIST_NUM(c->AccountList);i++)\r
+                               {\r
+                                       ACCOUNT *a = LIST_DATA(c->AccountList, i);\r
+                                       if (a != r)\r
+                                       {\r
+                                               if (StrCmpi(a->ClientOption->DeviceName,\r
+                                                       r->ClientOption->DeviceName) == 0)\r
+                                               {\r
+                                                       if (a->ClientSession != NULL)\r
+                                                       {\r
+                                                               already_used = true;\r
+                                                               break;\r
+                                                       }\r
+                                               }\r
+                                       }\r
+                               }\r
+\r
+                               if (already_used)\r
+                               {\r
+                                       CiSetError(c, ERR_VLAN_FOR_ACCOUNT_USED);\r
+                               }\r
+                               else\r
+                               {\r
+                                       // 接続を開始\r
+                                       PACKET_ADAPTER *pa = VLanGetPacketAdapter();\r
+\r
+                                       if (r->ClientAuth->AuthType == CLIENT_AUTHTYPE_SECURE)\r
+                                       {\r
+                                               // セキュアデバイス認証のためのプロシージャを登録する\r
+                                               r->ClientAuth->SecureSignProc = CiSecureSignProc;\r
+                                       }\r
+                                       else\r
+                                       {\r
+                                               r->ClientAuth->SecureSignProc = NULL;\r
+                                       }\r
+\r
+                                       if (r->CheckServerCert)\r
+                                       {\r
+                                               // サーバー証明書確認のためのプロシージャを登録する\r
+                                               r->ClientAuth->CheckCertProc = CiCheckCertProc;\r
+                                       }\r
+                                       else\r
+                                       {\r
+                                               r->ClientAuth->CheckCertProc = NULL;\r
+                                       }\r
+\r
+                                       r->StatusPrinter = CiClientStatusPrinter;\r
+                                       r->LastConnectDateTime = SystemTime64();\r
+\r
+                                       CLog(c, "LC_CONNECT", connect->AccountName);\r
+\r
+                                       r->ClientSession = NewClientSessionEx(c->Cedar, r->ClientOption, r->ClientAuth, pa, r);\r
+                                       Notify(r->ClientSession, CLIENT_NOTIFY_ACCOUNT_CHANGED);\r
+\r
+                                       ret = true;\r
+                               }\r
+                       }\r
+               }\r
+               Unlock(r->lock);\r
+\r
+       }\r
+       UnlockList(c->AccountList);\r
+\r
+       CiSaveConfigurationFile(c);\r
+\r
+       return ret;\r
+}\r
+\r
+// アカウント情報の取得\r
+bool CtGetAccount(CLIENT *c, RPC_CLIENT_GET_ACCOUNT *a)\r
+{\r
+       // 引数チェック\r
+       if (c == NULL || a == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       LockList(c->AccountList);\r
+       {\r
+               ACCOUNT t, *r;\r
+\r
+               // アカウントを検索\r
+               t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));\r
+               UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), a->AccountName);\r
+\r
+               r = Search(c->AccountList, &t);\r
+               if (r == NULL)\r
+               {\r
+                       // 指定したアカウントは見つからない\r
+                       UnlockList(c->AccountList);\r
+\r
+                       Free(t.ClientOption);\r
+                       CiSetError(c, ERR_ACCOUNT_NOT_FOUND);\r
+                       return false;\r
+               }\r
+\r
+               Free(t.ClientOption);\r
+\r
+               Lock(r->lock);\r
+               {\r
+                       // クライアントオプションをコピー\r
+                       if (a->ClientOption != NULL)\r
+                       {\r
+                               Free(a->ClientOption);\r
+                       }\r
+                       a->ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));\r
+                       Copy(a->ClientOption, r->ClientOption, sizeof(CLIENT_OPTION));\r
+\r
+                       // 認証データをコピー\r
+                       if (a->ClientAuth != NULL)\r
+                       {\r
+                               CiFreeClientAuth(a->ClientAuth);\r
+                       }\r
+                       a->ClientAuth = CopyClientAuth(r->ClientAuth);\r
+\r
+                       a->StartupAccount = r->StartupAccount;\r
+\r
+                       a->CheckServerCert = r->CheckServerCert;\r
+                       a->ServerCert = NULL;\r
+                       if (r->ServerCert != NULL)\r
+                       {\r
+                               a->ServerCert = CloneX(r->ServerCert);\r
+                       }\r
+\r
+                       // ショートカットキー\r
+                       Copy(a->ShortcutKey, r->ShortcutKey, SHA1_SIZE);\r
+\r
+                       a->CreateDateTime = r->CreateDateTime;\r
+                       a->LastConnectDateTime = r->LastConnectDateTime;\r
+                       a->UpdateDateTime = r->UpdateDateTime;\r
+               }\r
+               Unlock(r->lock);\r
+\r
+       }\r
+       UnlockList(c->AccountList);\r
+\r
+       return true;\r
+}\r
+\r
+// アカウント名の変更\r
+bool CtRenameAccount(CLIENT *c, RPC_RENAME_ACCOUNT *rename)\r
+{\r
+       bool ret;\r
+       // 引数チェック\r
+       if (c == NULL || rename == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       ret = false;\r
+\r
+       if (UniStrCmp(rename->NewName, rename->OldName) == 0)\r
+       {\r
+               // 名前が変更されていない\r
+               return true;\r
+       }\r
+\r
+       LockList(c->AccountList);\r
+       {\r
+               ACCOUNT t, *r, *r2;\r
+\r
+               if (UniStrLen(rename->NewName) == 0)\r
+               {\r
+                       // 名前が不正\r
+                       CiSetError(c, ERR_INVALID_VALUE);\r
+                       UnlockList(c->AccountList);\r
+                       return false;\r
+               }\r
+\r
+               // 古いアカウント名を検索\r
+               t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));\r
+               UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), rename->OldName);\r
+\r
+               r = Search(c->AccountList, &t);\r
+               if (r == NULL)\r
+               {\r
+                       // 指定したアカウントは見つからない\r
+                       UnlockList(c->AccountList);\r
+\r
+                       Free(t.ClientOption);\r
+                       CiSetError(c, ERR_ACCOUNT_NOT_FOUND);\r
+                       return false;\r
+               }\r
+\r
+               Free(t.ClientOption);\r
+\r
+               // 新しいアカウント名を検索\r
+               t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));\r
+               UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), rename->NewName);\r
+\r
+               r2 = Search(c->AccountList, &t);\r
+               if (r2 != NULL)\r
+               {\r
+                       // 指定した名前のアカウントはすでに存在する\r
+                       UnlockList(c->AccountList);\r
+\r
+                       Free(t.ClientOption);\r
+                       CiSetError(c, ERR_ACCOUNT_ALREADY_EXISTS);\r
+                       return false;\r
+               }\r
+\r
+               Free(t.ClientOption);\r
+\r
+               Lock(r->lock);\r
+               {\r
+                       // アカウントの動作状態チェック\r
+                       if (r->ClientSession != NULL)\r
+                       {\r
+                               // アカウントは動作中\r
+                               Unlock(r->lock);\r
+                               UnlockList(c->AccountList);\r
+                               CiSetError(c, ERR_ACCOUNT_ACTIVE);\r
+\r
+                               return false;\r
+                       }\r
+\r
+                       // アカウント名を更新\r
+                       UniStrCpy(r->ClientOption->AccountName, sizeof(r->ClientOption->AccountName),\r
+                               rename->NewName);\r
+\r
+                       CLog(c, "LC_RENAME_ACCOUNT", rename->OldName, rename->NewName);\r
+\r
+                       ret = true;\r
+               }\r
+               Unlock(r->lock);\r
+\r
+               Sort(c->AccountList);\r
+\r
+       }\r
+       UnlockList(c->AccountList);\r
+\r
+       CiSaveConfigurationFile(c);\r
+\r
+       CiNotify(c);\r
+\r
+       return ret;\r
+}\r
+\r
+// クライアント設定の設定\r
+bool CtSetClientConfig(CLIENT *c, CLIENT_CONFIG *o)\r
+{\r
+       KEEP *k;\r
+       // 引数チェック\r
+       if (c == NULL || o == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       if (o->UseKeepConnect)\r
+       {\r
+               if (IsEmptyStr(o->KeepConnectHost) ||\r
+                       o->KeepConnectPort == 0 ||\r
+                       o->KeepConnectPort >= 65536)\r
+               {\r
+                       CiSetError(c, ERR_INVALID_PARAMETER);\r
+                       return false;\r
+               }\r
+       }\r
+\r
+       Lock(c->lock);\r
+       {\r
+               Copy(&c->Config, o, sizeof(CLIENT_CONFIG));\r
+       }\r
+       Unlock(c->lock);\r
+\r
+       // 設定の保存\r
+       CiSaveConfigurationFile(c);\r
+\r
+       // Keep Connect の適用\r
+       k = c->Keep;\r
+       Lock(k->lock);\r
+       {\r
+               if (o->UseKeepConnect)\r
+               {\r
+                       StrCpy(k->ServerName, sizeof(k->ServerName), c->Config.KeepConnectHost);\r
+                       k->ServerPort = c->Config.KeepConnectPort;\r
+                       k->Interval = c->Config.KeepConnectInterval * 1000;\r
+                       k->UdpMode = (c->Config.KeepConnectProtocol == CONNECTION_UDP) ? true : false;\r
+                       k->Enable = true;\r
+               }\r
+               else\r
+               {\r
+                       k->Enable = false;\r
+               }\r
+       }\r
+       Unlock(k->lock);\r
+\r
+       return true;\r
+}\r
+\r
+// ククライアント設定の取得\r
+bool CtGetClientConfig(CLIENT *c, CLIENT_CONFIG *o)\r
+{\r
+       // 引数チェック\r
+       if (c == NULL || o == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       Lock(c->lock);\r
+       {\r
+               Copy(o, &c->Config, sizeof(CLIENT_CONFIG));\r
+       }\r
+       Unlock(c->lock);\r
+\r
+       return true;\r
+}\r
+\r
+// アカウントのスタートアップ属性を解除する\r
+bool CtRemoveStartupAccount(CLIENT *c, RPC_CLIENT_DELETE_ACCOUNT *a)\r
+{\r
+       bool ret;\r
+       // 引数チェック\r
+       if (c == NULL || a == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       ret = false;\r
+\r
+       LockList(c->AccountList);\r
+       {\r
+               ACCOUNT t, *r;\r
+               // アカウントの検索\r
+\r
+               t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));\r
+               UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), a->AccountName);\r
+\r
+               r = Search(c->AccountList, &t);\r
+               if (r == NULL)\r
+               {\r
+                       // 指定したアカウントは見つからない\r
+                       UnlockList(c->AccountList);\r
+\r
+                       Free(t.ClientOption);\r
+                       CiSetError(c, ERR_ACCOUNT_NOT_FOUND);\r
+                       return false;\r
+               }\r
+\r
+               Free(t.ClientOption);\r
+\r
+               Lock(r->lock);\r
+               {\r
+                       // スタートアップアカウントを解除する\r
+                       ret = true;\r
+                       r->StartupAccount = false;\r
+               }\r
+               Unlock(r->lock);\r
+       }\r
+       UnlockList(c->AccountList);\r
+\r
+       if (ret)\r
+       {\r
+               CiSaveConfigurationFile(c);\r
+               CiNotify(c);\r
+       }\r
+\r
+       return ret;\r
+}\r
+\r
+// アカウントをスタートアップアカウントにする\r
+bool CtSetStartupAccount(CLIENT *c, RPC_CLIENT_DELETE_ACCOUNT *a)\r
+{\r
+       bool ret;\r
+       // 引数チェック\r
+       if (c == NULL || a == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       ret = false;\r
+\r
+       LockList(c->AccountList);\r
+       {\r
+               ACCOUNT t, *r;\r
+               // アカウントの検索\r
+\r
+               t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));\r
+               UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), a->AccountName);\r
+\r
+               r = Search(c->AccountList, &t);\r
+               if (r == NULL)\r
+               {\r
+                       // 指定したアカウントは見つからない\r
+                       UnlockList(c->AccountList);\r
+\r
+                       Free(t.ClientOption);\r
+                       CiSetError(c, ERR_ACCOUNT_NOT_FOUND);\r
+                       return false;\r
+               }\r
+\r
+               Free(t.ClientOption);\r
+\r
+               Lock(r->lock);\r
+               {\r
+                       // スタートアップアカウントにする\r
+                       ret = true;\r
+                       r->StartupAccount = true;\r
+               }\r
+               Unlock(r->lock);\r
+       }\r
+       UnlockList(c->AccountList);\r
+\r
+       if (ret)\r
+       {\r
+               CiSaveConfigurationFile(c);\r
+               CiNotify(c);\r
+       }\r
+\r
+       return ret;\r
+}\r
+\r
+// アカウントの削除\r
+bool CtDeleteAccount(CLIENT *c, RPC_CLIENT_DELETE_ACCOUNT *a)\r
+{\r
+       bool ret;\r
+       // 引数チェック\r
+       if (c == NULL || a == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       ret = false;\r
+\r
+       LockList(c->AccountList);\r
+       {\r
+               ACCOUNT t, *r;\r
+               // アカウントの検索\r
+\r
+               t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));\r
+               UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), a->AccountName);\r
+\r
+               r = Search(c->AccountList, &t);\r
+               if (r == NULL)\r
+               {\r
+                       // 指定したアカウントは見つからない\r
+                       UnlockList(c->AccountList);\r
+\r
+                       Free(t.ClientOption);\r
+                       CiSetError(c, ERR_ACCOUNT_NOT_FOUND);\r
+                       return false;\r
+               }\r
+\r
+               Free(t.ClientOption);\r
+\r
+               Lock(r->lock);\r
+               {\r
+                       // アカウントの動作状態チェック\r
+                       if (r->ClientSession != NULL)\r
+                       {\r
+                               // アカウントは動作中\r
+                               Unlock(r->lock);\r
+                               UnlockList(c->AccountList);\r
+                               CiSetError(c, ERR_ACCOUNT_ACTIVE);\r
+\r
+                               return false;\r
+                       }\r
+\r
+                       // このアカウントをリストから削除する\r
+                       Delete(c->AccountList, r);\r
+               }\r
+               Unlock(r->lock);\r
+\r
+               // このアカウントのメモリを解放する\r
+               CiFreeAccount(r);\r
+\r
+               CLog(c, "LC_DELETE_ACCOUNT", a->AccountName);\r
+               ret = true;\r
+\r
+       }\r
+       UnlockList(c->AccountList);\r
+\r
+       if (ret)\r
+       {\r
+               CiSaveConfigurationFile(c);\r
+               CiNotify(c);\r
+       }\r
+\r
+       return ret;\r
+}\r
+\r
+// アカウントの列挙\r
+bool CtEnumAccount(CLIENT *c, RPC_CLIENT_ENUM_ACCOUNT *e)\r
+{\r
+       // 引数チェック\r
+       if (c == NULL || e == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       LockList(c->AccountList);\r
+       {\r
+               UINT i;\r
+               // アカウント件数\r
+               e->NumItem = LIST_NUM(c->AccountList);\r
+               e->Items = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_ACCOUNT_ITEM *) * e->NumItem);\r
+\r
+               for (i = 0;i < e->NumItem;i++)\r
+               {\r
+                       ACCOUNT *a = LIST_DATA(c->AccountList, i);\r
+                       RPC_CLIENT_ENUM_ACCOUNT_ITEM *item = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_ACCOUNT_ITEM));\r
+                       e->Items[i] = item;\r
+\r
+                       // アカウント名\r
+                       UniStrCpy(item->AccountName, sizeof(item->AccountName), a->ClientOption->AccountName);\r
+\r
+                       // ユーザー名\r
+                       StrCpy(item->UserName, sizeof(item->UserName), a->ClientAuth->Username);\r
+\r
+                       // サーバー名\r
+                       StrCpy(item->ServerName, sizeof(item->ServerName), a->ClientOption->Hostname);\r
+\r
+                       // プロキシ種類\r
+                       item->ProxyType = a->ClientOption->ProxyType;\r
+\r
+                       // デバイス名\r
+                       StrCpy(item->DeviceName, sizeof(item->DeviceName), a->ClientOption->DeviceName);\r
+\r
+                       // プロキシ情報\r
+                       if (item->ProxyType != PROXY_DIRECT)\r
+                       {\r
+                               StrCpy(item->ProxyName, sizeof(item->ProxyName), a->ClientOption->ProxyName);\r
+                       }\r
+\r
+                       // スタートアップ\r
+                       item->StartupAccount = a->StartupAccount;\r
+\r
+                       // 動作フラグ\r
+                       item->Active = (a->ClientSession == NULL ? false : true);\r
+\r
+                       // 接続フラグ\r
+                       item->Connected = (item->Active == false) ? false : a->ClientSession->ConnectSucceed;\r
+\r
+                       // ポート番号\r
+                       item->Port = a->ClientOption->Port;\r
+\r
+                       // 仮想 HUB 名\r
+                       StrCpy(item->HubName, sizeof(item->HubName), a->ClientOption->HubName);\r
+\r
+                       item->CreateDateTime = a->CreateDateTime;\r
+                       item->LastConnectDateTime = a->LastConnectDateTime;\r
+                       item->UpdateDateTime = a->UpdateDateTime;\r
+               }\r
+       }\r
+       UnlockList(c->AccountList);\r
+\r
+       return true;\r
+}\r
+\r
+// アカウントの設定\r
+bool CtSetAccount(CLIENT *c, RPC_CLIENT_CREATE_ACCOUNT *a)\r
+{\r
+       // 引数チェック\r
+       if (c == NULL || a == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       // 既存のアカウントが存在するかどうかチェック\r
+       LockList(c->AccountList);\r
+       {\r
+               ACCOUNT t, *ret;\r
+               t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));\r
+               UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName),\r
+                       a->ClientOption->AccountName);\r
+\r
+               ret = Search(c->AccountList, &t);\r
+               if (ret == NULL)\r
+               {\r
+                       // 存在しない\r
+                       UnlockList(c->AccountList);\r
+                       Free(t.ClientOption);\r
+\r
+                       CiSetError(c, ERR_ACCOUNT_NOT_FOUND);\r
+\r
+                       return false;\r
+               }\r
+               Free(t.ClientOption);\r
+\r
+               if (a->ClientAuth->AuthType == CLIENT_AUTHTYPE_CERT)\r
+               {\r
+                       if (a->ClientAuth->ClientX == NULL ||\r
+                               a->ClientAuth->ClientX->is_compatible_bit == false ||\r
+                               a->ClientAuth->ClientK == NULL)\r
+                       {\r
+                               // クライアント証明書が不正\r
+                               UnlockList(c->AccountList);\r
+                               CiSetError(c, ERR_NOT_RSA_1024);\r
+                               return false;\r
+                       }\r
+               }\r
+\r
+               if (a->ServerCert != NULL && a->ServerCert->is_compatible_bit == false)\r
+               {\r
+                       // サーバー証明書が不正\r
+                       UnlockList(c->AccountList);\r
+                       CiSetError(c, ERR_NOT_RSA_1024);\r
+                       return false;\r
+               }\r
+\r
+               Lock(ret->lock);\r
+               {\r
+\r
+#if    0\r
+                       // 現在のバージョンではアカウント動作中でも設定の書き換えは行われる\r
+                       // (ただし次回接続時まで設定は適用されない)\r
+                       if (ret->ClientSession != NULL)\r
+                       {\r
+                               // アカウントが動作中である\r
+                               Unlock(ret->lock);\r
+                               UnlockList(c->AccountList);\r
+\r
+                               CiSetError(c, ERR_ACCOUNT_ACTIVE);\r
+\r
+                               return false;\r
+                       }\r
+#endif\r
+\r
+                       // クライアント認証データの削除\r
+                       CiFreeClientAuth(ret->ClientAuth);\r
+\r
+                       // クライアント認証データのコピー\r
+                       ret->ClientAuth = CopyClientAuth(a->ClientAuth);\r
+\r
+                       // クライアントオプションの削除\r
+                       Free(ret->ClientOption);\r
+\r
+                       // クライアントオプションのコピー\r
+                       ret->ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));\r
+                       Copy(ret->ClientOption, a->ClientOption, sizeof(CLIENT_OPTION));\r
+\r
+                       ret->StartupAccount = a->StartupAccount;\r
+\r
+                       ret->CheckServerCert = a->CheckServerCert;\r
+\r
+                       if (a->ServerCert != NULL)\r
+                       {\r
+                               if (ret->ServerCert != NULL)\r
+                               {\r
+                                       FreeX(ret->ServerCert);\r
+                               }\r
+                               ret->ServerCert = CloneX(a->ServerCert);\r
+                       }\r
+                       else\r
+                       {\r
+                               if (ret->ServerCert != NULL)\r
+                               {\r
+                                       FreeX(ret->ServerCert);\r
+                               }\r
+                               ret->ServerCert = false;\r
+                       }\r
+\r
+                       ret->UpdateDateTime = SystemTime64();\r
+               }\r
+               Unlock(ret->lock);\r
+       }\r
+       UnlockList(c->AccountList);\r
+\r
+       CiSaveConfigurationFile(c);\r
+\r
+       CiNotify(c);\r
+\r
+       return true;\r
+}\r
+\r
+// アカウントの作成\r
+bool CtCreateAccount(CLIENT *c, RPC_CLIENT_CREATE_ACCOUNT *a)\r
+{\r
+       // 引数チェック\r
+       if (c == NULL || a == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       // 既存のアカウントが存在するかどうかチェック\r
+       LockList(c->AccountList);\r
+       {\r
+               ACCOUNT t, *ret, *new_account;\r
+               t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));\r
+               UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName),\r
+                       a->ClientOption->AccountName);\r
+\r
+               ret = Search(c->AccountList, &t);\r
+               if (ret != NULL)\r
+               {\r
+                       // すでに存在する\r
+                       UnlockList(c->AccountList);\r
+                       Free(t.ClientOption);\r
+\r
+                       CiSetError(c, ERR_ACCOUNT_ALREADY_EXISTS);\r
+\r
+                       return false;\r
+               }\r
+\r
+               Free(t.ClientOption);\r
+\r
+               if (UniStrLen(a->ClientOption->AccountName) == 0)\r
+               {\r
+                       // 名前が不正\r
+                       UnlockList(c->AccountList);\r
+                       CiSetError(c, ERR_INVALID_VALUE);\r
+                       return false;\r
+               }\r
+\r
+               if (a->ClientAuth->AuthType == CLIENT_AUTHTYPE_CERT)\r
+               {\r
+                       if (a->ClientAuth->ClientX == NULL ||\r
+                               a->ClientAuth->ClientX->is_compatible_bit == false ||\r
+                               a->ClientAuth->ClientK == NULL)\r
+                       {\r
+                               // クライアント証明書が不正\r
+                               UnlockList(c->AccountList);\r
+                               CiSetError(c, ERR_NOT_RSA_1024);\r
+                               return false;\r
+                       }\r
+               }\r
+\r
+               if (a->ServerCert != NULL && a->ServerCert->is_compatible_bit == false)\r
+               {\r
+                       // サーバー証明書が不正\r
+                       UnlockList(c->AccountList);\r
+                       CiSetError(c, ERR_NOT_RSA_1024);\r
+                       return false;\r
+               }\r
+\r
+               // 新しいアカウントを追加する\r
+               new_account = ZeroMalloc(sizeof(ACCOUNT));\r
+               new_account->lock = NewLock();\r
+\r
+               // クライアント認証データのコピー\r
+               new_account->ClientAuth = CopyClientAuth(a->ClientAuth);\r
+\r
+               // クライアントオプションのコピー\r
+               new_account->ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));\r
+               Copy(new_account->ClientOption, a->ClientOption, sizeof(CLIENT_OPTION));\r
+\r
+               new_account->StartupAccount = a->StartupAccount;\r
+\r
+               new_account->CheckServerCert = a->CheckServerCert;\r
+               if (a->ServerCert != NULL)\r
+               {\r
+                       new_account->ServerCert = CloneX(a->ServerCert);\r
+               }\r
+\r
+               // ショートカットキー\r
+               if (IsZero(a->ShortcutKey, SHA1_SIZE))\r
+               {\r
+                       Rand(new_account->ShortcutKey, SHA1_SIZE);\r
+               }\r
+               else\r
+               {\r
+                       Copy(new_account->ShortcutKey, a->ShortcutKey, SHA1_SIZE);\r
+               }\r
+\r
+               new_account->CreateDateTime = new_account->UpdateDateTime = SystemTime64();\r
+\r
+               // リストに挿入する\r
+               Insert(c->AccountList, new_account);\r
+\r
+               CLog(c, "LC_NEW_ACCOUNT", a->ClientOption->AccountName);\r
+       }\r
+       UnlockList(c->AccountList);\r
+\r
+       CiNormalizeAccountVLan(c);\r
+\r
+       CiSaveConfigurationFile(c);\r
+\r
+       CiNotify(c);\r
+\r
+       return true;\r
+}\r
+\r
+// アカウント取得構造体の解放\r
+void CiFreeClientGetAccount(RPC_CLIENT_GET_ACCOUNT *a)\r
+{\r
+       // 引数チェック\r
+       if (a == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       // アカウント情報の解放\r
+       if (a->ServerCert != NULL)\r
+       {\r
+               FreeX(a->ServerCert);\r
+       }\r
+       CiFreeClientAuth(a->ClientAuth);\r
+       Free(a->ClientOption);\r
+}\r
+\r
+// アカウント作成構造体の解放\r
+void CiFreeClientCreateAccount(RPC_CLIENT_CREATE_ACCOUNT *a)\r
+{\r
+       // 引数チェック\r
+       if (a == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       // アカウント情報の解放\r
+       if (a->ServerCert != NULL)\r
+       {\r
+               FreeX(a->ServerCert);\r
+       }\r
+       CiFreeClientAuth(a->ClientAuth);\r
+       Free(a->ClientOption);\r
+}\r
+\r
+// 仮想 LAN カードの停止\r
+bool CtDisableVLan(CLIENT *c, RPC_CLIENT_CREATE_VLAN *vlan)\r
+{\r
+       UINT i;\r
+       bool used;\r
+       // 引数チェック\r
+       if (c == NULL || vlan == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+#ifndef        OS_WIN32\r
+\r
+       if (GetOsInfo()->OsType == OSTYPE_MACOS_X)\r
+       {\r
+               // MacOS X では仮想 LAN カードは増減できない\r
+               CiSetError(c, ERR_NOT_SUPPORTED);\r
+               return false;\r
+       }\r
+\r
+       // 指定した名前の仮想 LAN カードが 1 つ以上のアカウントによって使用されていない\r
+       // かどうか確認する\r
+       used = false;\r
+       LockList(c->AccountList);\r
+       {\r
+               for (i = 0;i < LIST_NUM(c->AccountList);i++)\r
+               {\r
+                       ACCOUNT *a = LIST_DATA(c->AccountList, i);\r
+                       if (StrCmpi(a->ClientOption->DeviceName, vlan->DeviceName) == 0)\r
+                       {\r
+                               Lock(a->lock);\r
+                               {\r
+                                       if (a->ClientSession != NULL)\r
+                                       {\r
+                                               used = true;\r
+                                       }\r
+                               }\r
+                               Unlock(a->lock);\r
+                       }\r
+               }\r
+       }\r
+       UnlockList(c->AccountList);\r
+\r
+       // 仮想 LAN カードを検索する\r
+       LockList(c->UnixVLanList);\r
+       {\r
+               UNIX_VLAN *v, t;\r
+\r
+               Zero(&t, sizeof(t));\r
+               StrCpy(t.Name, sizeof(t.Name), vlan->DeviceName);\r
+\r
+               v = Search(c->UnixVLanList, &t);\r
+               if (v == NULL)\r
+               {\r
+                       UnlockList(c->UnixVLanList);\r
+                       CiSetError(c, ERR_OBJECT_NOT_FOUND);\r
+                       return false;\r
+               }\r
+\r
+               // 停止する\r
+               v->Enabled = false;\r
+       }\r
+       UnlockList(c->UnixVLanList);\r
+\r
+       CiSaveConfigurationFile(c);\r
+       CiNotify(c);\r
+\r
+       return true;\r
+\r
+#else  // OS_WIN32\r
+\r
+       // 指定した名前の仮想 LAN カードが 1 つ以上のアカウントによって使用されていない\r
+       // かどうか確認する\r
+       used = false;\r
+       LockList(c->AccountList);\r
+       {\r
+               for (i = 0;i < LIST_NUM(c->AccountList);i++)\r
+               {\r
+                       ACCOUNT *a = LIST_DATA(c->AccountList, i);\r
+                       if (StrCmpi(a->ClientOption->DeviceName, vlan->DeviceName) == 0)\r
+                       {\r
+                               Lock(a->lock);\r
+                               {\r
+                                       if (a->ClientSession != NULL)\r
+                                       {\r
+                                               used = true;\r
+                                       }\r
+                               }\r
+                               Unlock(a->lock);\r
+                       }\r
+               }\r
+       }\r
+       UnlockList(c->AccountList);\r
+\r
+#if    0\r
+       if (used)\r
+       {\r
+               // 使用中\r
+               CiSetError(c, ERR_VLAN_IS_USED);\r
+               return false;\r
+       }\r
+#endif\r
+\r
+\r
+       // 仮想 LAN カードが存在しているかチェック\r
+       if (MsIsVLanExists(VLAN_ADAPTER_NAME_TAG, vlan->DeviceName) == false)\r
+       {\r
+               CiSetError(c, ERR_OBJECT_NOT_FOUND);\r
+               CiNotify(c);\r
+               return false;\r
+       }\r
+\r
+\r
+       if (MsIs64BitWindows() && Is32() && MsIsAdmin())\r
+       {\r
+               // Windows は 64 bit だがこのコードは 32 bit であるので\r
+               // driver_installer を起動して処理を実行する\r
+               char tmp[MAX_SIZE];\r
+\r
+               Format(tmp, sizeof(tmp), "disablevlan %s", vlan->DeviceName);\r
+\r
+               if (MsExecDriverInstaller(tmp) == false)\r
+               {\r
+                       CiSetError(c, ERR_VLAN_INSTALL_ERROR);\r
+                       CiNotify(c);\r
+                       return false;\r
+               }\r
+       }\r
+       else\r
+       {\r
+               // 仮想 LAN カードを停止\r
+               if (MsDisableVLan(vlan->DeviceName) == false)\r
+               {\r
+                       CiSetError(c, ERR_VLAN_INSTALL_ERROR);\r
+                       CiNotify(c);\r
+                       return false;\r
+               }\r
+       }\r
+\r
+       CiNotify(c);\r
+\r
+       return true;\r
+\r
+#endif // OS_WIN32\r
+\r
+}\r
+\r
+// 仮想 LAN カードの開始\r
+bool CtEnableVLan(CLIENT *c, RPC_CLIENT_CREATE_VLAN *vlan)\r
+{\r
+       // 引数チェック\r
+       if (c == NULL || vlan == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+#ifndef        OS_WIN32\r
+\r
+       if (GetOsInfo()->OsType == OSTYPE_MACOS_X)\r
+       {\r
+               // MacOS X では仮想 LAN カードは増減できない\r
+               CiSetError(c, ERR_NOT_SUPPORTED);\r
+               return false;\r
+       }\r
+\r
+       // 仮想 LAN カードを検索する\r
+       LockList(c->UnixVLanList);\r
+       {\r
+               UNIX_VLAN *v, t;\r
+\r
+               Zero(&t, sizeof(t));\r
+               StrCpy(t.Name, sizeof(t.Name), vlan->DeviceName);\r
+\r
+               v = Search(c->UnixVLanList, &t);\r
+               if (v == NULL)\r
+               {\r
+                       UnlockList(c->UnixVLanList);\r
+                       CiSetError(c, ERR_OBJECT_NOT_FOUND);\r
+                       return false;\r
+               }\r
+\r
+               // 有効にする\r
+               v->Enabled = true;\r
+       }\r
+       UnlockList(c->UnixVLanList);\r
+\r
+       CiSaveConfigurationFile(c);\r
+       CiNotify(c);\r
+\r
+       return true;\r
+\r
+#else  // OS_WIN32\r
+\r
+       // 仮想 LAN カードが存在しているかチェック\r
+       if (MsIsVLanExists(VLAN_ADAPTER_NAME_TAG, vlan->DeviceName) == false)\r
+       {\r
+               CiSetError(c, ERR_OBJECT_NOT_FOUND);\r
+               CiNotify(c);\r
+               return false;\r
+       }\r
+\r
+       if (MsIs64BitWindows() && Is32() && MsIsAdmin())\r
+       {\r
+               // Windows は 64 bit だがこのコードは 32 bit であるので\r
+               // driver_installer を起動して処理を実行する\r
+               char tmp[MAX_SIZE];\r
+\r
+               Format(tmp, sizeof(tmp), "enablevlan %s", vlan->DeviceName);\r
+\r
+               if (MsExecDriverInstaller(tmp) == false)\r
+               {\r
+                       CiSetError(c, ERR_VLAN_INSTALL_ERROR);\r
+                       CiNotify(c);\r
+                       return false;\r
+               }\r
+       }\r
+       else\r
+       {\r
+               // 仮想 LAN カードを開始\r
+               if (MsEnableVLan(vlan->DeviceName) == false)\r
+               {\r
+                       CiSetError(c, ERR_VLAN_INSTALL_ERROR);\r
+                       CiNotify(c);\r
+                       return false;\r
+               }\r
+       }\r
+\r
+       CiNotify(c);\r
+\r
+       return true;\r
+\r
+#endif // OS_WIN32\r
+\r
+}\r
+\r
+// 仮想 LAN カードの削除\r
+bool CtDeleteVLan(CLIENT *c, RPC_CLIENT_CREATE_VLAN *d)\r
+{\r
+       UINT i;\r
+       bool used;\r
+       // 引数チェック\r
+       if (c == NULL || d == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+#ifndef        OS_WIN32\r
+\r
+       if (GetOsInfo()->OsType == OSTYPE_MACOS_X)\r
+       {\r
+               // MacOS X では仮想 LAN カードは増減できない\r
+               CiSetError(c, ERR_NOT_SUPPORTED);\r
+               return false;\r
+       }\r
+\r
+       // 指定した名前の仮想 LAN カードが 1 つ以上のアカウントによって使用されていない\r
+       // かどうか確認する\r
+       used = false;\r
+       LockList(c->AccountList);\r
+       {\r
+               for (i = 0;i < LIST_NUM(c->AccountList);i++)\r
+               {\r
+                       ACCOUNT *a = LIST_DATA(c->AccountList, i);\r
+                       if (StrCmpi(a->ClientOption->DeviceName, d->DeviceName) == 0)\r
+                       {\r
+                               used = true;\r
+                       }\r
+               }\r
+       }\r
+       UnlockList(c->AccountList);\r
+\r
+#if    0\r
+       if (used)\r
+       {\r
+               // 使用中\r
+               CiSetError(c, ERR_VLAN_IS_USED);\r
+               return false;\r
+       }\r
+#endif\r
+\r
+       // 仮想 LAN カードを検索する\r
+       LockList(c->UnixVLanList);\r
+       {\r
+               UNIX_VLAN *v, t;\r
+\r
+               Zero(&t, sizeof(t));\r
+               StrCpy(t.Name, sizeof(t.Name), d->DeviceName);\r
+\r
+               v = Search(c->UnixVLanList, &t);\r
+               if (v == NULL)\r
+               {\r
+                       UnlockList(c->UnixVLanList);\r
+                       CiSetError(c, ERR_OBJECT_NOT_FOUND);\r
+                       return false;\r
+               }\r
+\r
+               // 削除する\r
+               if (Delete(c->UnixVLanList, v))\r
+               {\r
+                       Free(v);\r
+               }\r
+\r
+               CLog(c, "LC_DELETE_VLAN", d->DeviceName);\r
+\r
+               UnixVLanDelete(d->DeviceName);\r
+       }\r
+       UnlockList(c->UnixVLanList);\r
+\r
+       CiNormalizeAccountVLan(c);\r
+\r
+       CiSaveConfigurationFile(c);\r
+       CiNotify(c);\r
+\r
+       return true;\r
+\r
+#else  // OS_WIN32\r
+\r
+       if (MsIsNt() == false)\r
+       {\r
+               // Win9x では使用できない\r
+               CiSetError(c, ERR_NOT_SUPPORTED);\r
+               return false;\r
+       }\r
+\r
+       // 仮想 LAN カードが存在しているかチェック\r
+       if (MsIsVLanExists(VLAN_ADAPTER_NAME_TAG, d->DeviceName) == false)\r
+       {\r
+               CiSetError(c, ERR_OBJECT_NOT_FOUND);\r
+               return false;\r
+       }\r
+\r
+       // 指定した名前の仮想 LAN カードが 1 つ以上のアカウントによって使用されていない\r
+       // かどうか確認する\r
+       used = false;\r
+       LockList(c->AccountList);\r
+       {\r
+               for (i = 0;i < LIST_NUM(c->AccountList);i++)\r
+               {\r
+                       ACCOUNT *a = LIST_DATA(c->AccountList, i);\r
+                       if (StrCmpi(a->ClientOption->DeviceName, d->DeviceName) == 0)\r
+                       {\r
+                               used = true;\r
+                       }\r
+               }\r
+       }\r
+       UnlockList(c->AccountList);\r
+\r
+#if    0\r
+       if (used)\r
+       {\r
+               // 使用中\r
+               CiSetError(c, ERR_VLAN_IS_USED);\r
+               return false;\r
+       }\r
+#endif\r
+\r
+       if (MsIs64BitWindows() && Is32() && MsIsAdmin())\r
+       {\r
+               // Windows は 64 bit だがこのコードは 32 bit であるので\r
+               // driver_installer を起動して処理を実行する\r
+               char tmp[MAX_SIZE];\r
+\r
+               Format(tmp, sizeof(tmp), "uninstvlan %s", d->DeviceName);\r
+\r
+               if (MsExecDriverInstaller(tmp) == false)\r
+               {\r
+                       CiSetError(c, ERR_VLAN_INSTALL_ERROR);\r
+                       return false;\r
+               }\r
+       }\r
+       else\r
+       {\r
+               // 仮想 LAN カードを直接削除\r
+               if (MsUninstallVLan(d->DeviceName) == false)\r
+               {\r
+                       CiSetError(c, ERR_VLAN_INSTALL_ERROR);\r
+                       CiNotify(c);\r
+                       return false;\r
+               }\r
+       }\r
+\r
+       CLog(c, "LC_DELETE_VLAN", d->DeviceName);\r
+\r
+       CiNormalizeAccountVLan(c);\r
+\r
+       CiNotify(c);\r
+\r
+       return true;\r
+\r
+#endif // OS_WIN32\r
+\r
+}\r
+\r
+// 最初の VLAN の名前を取得\r
+char *CiGetFirstVLan(CLIENT *c)\r
+{\r
+       char *ret = NULL;\r
+       RPC_CLIENT_ENUM_VLAN t;\r
+       // 引数チェック\r
+       if (c == NULL)\r
+       {\r
+               return NULL;\r
+       }\r
+\r
+       Zero(&t, sizeof(t));\r
+       if (CtEnumVLan(c, &t) == false)\r
+       {\r
+               return NULL;\r
+       }\r
+\r
+       if (t.NumItem >= 1)\r
+       {\r
+               UINT i;\r
+               char *tmp = t.Items[0]->DeviceName;\r
+\r
+               for (i = 0;i < t.NumItem;i++)\r
+               {\r
+                       if (t.Items[i]->Enabled)\r
+                       {\r
+                               tmp = t.Items[i]->DeviceName;\r
+                       }\r
+               }\r
+\r
+               ret = CopyStr(tmp);\r
+       }\r
+\r
+       CiFreeClientEnumVLan(&t);\r
+\r
+       return ret;\r
+}\r
+\r
+// 仮想 LAN カードの列挙\r
+bool CtEnumVLan(CLIENT *c, RPC_CLIENT_ENUM_VLAN *e)\r
+{\r
+       UINT i;\r
+       TOKEN_LIST *t;\r
+       // 引数チェック\r
+       if (c == NULL || e == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+#ifndef        OS_WIN32\r
+\r
+       LockList(c->UnixVLanList);\r
+       {\r
+               e->NumItem = LIST_NUM(c->UnixVLanList);\r
+               e->Items = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_VLAN_ITEM *) * e->NumItem);\r
+\r
+               for (i = 0;i < e->NumItem;i++)\r
+               {\r
+                       RPC_CLIENT_ENUM_VLAN_ITEM *item;\r
+                       UNIX_VLAN *v;\r
+\r
+                       v = LIST_DATA(c->UnixVLanList, i);\r
+                       e->Items[i] = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_VLAN_ITEM));\r
+                       item = e->Items[i];\r
+\r
+                       item->Enabled = v->Enabled;\r
+                       BinToStr(item->MacAddress, sizeof(item->MacAddress), v->MacAddress, 6);\r
+                       StrCpy(item->DeviceName, sizeof(item->DeviceName), v->Name);\r
+                       StrCpy(item->Version, sizeof(item->Version), c->Cedar->VerString);\r
+               }\r
+       }\r
+       UnlockList(c->UnixVLanList);\r
+\r
+       return true;\r
+\r
+#else  // OS_WIN32\r
+\r
+       // 列挙\r
+       t = MsEnumNetworkAdapters(VLAN_ADAPTER_NAME, "---dummy-string-ut--");\r
+       if (t == NULL)\r
+       {\r
+               // 列挙失敗\r
+               e->NumItem = 0;\r
+               e->Items = ZeroMalloc(0);\r
+       }\r
+       else\r
+       {\r
+               // 列挙成功\r
+               e->NumItem = t->NumTokens;\r
+               e->Items = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_VLAN_ITEM *) * e->NumItem);\r
+\r
+               for (i = 0;i < e->NumItem;i++)\r
+               {\r
+                       char *tmp;\r
+                       RPC_CLIENT_ENUM_VLAN_ITEM *item;\r
+                       e->Items[i] = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_VLAN_ITEM));\r
+                       item = e->Items[i];\r
+\r
+                       StrCpy(item->DeviceName, sizeof(item->DeviceName), t->Token[i]);\r
+                       item->Enabled = MsIsVLanEnabled(item->DeviceName);\r
+\r
+                       tmp = MsGetMacAddress(VLAN_ADAPTER_NAME_TAG, item->DeviceName);\r
+\r
+                       StrCpy(item->MacAddress, sizeof(item->MacAddress), tmp);\r
+                       Free(tmp);\r
+\r
+                       tmp = MsGetDriverVersion(VLAN_ADAPTER_NAME_TAG, item->DeviceName);\r
+\r
+                       StrCpy(item->Version, sizeof(item->Version), tmp);\r
+                       Free(tmp);\r
+               }\r
+\r
+               FreeToken(t);\r
+       }\r
+\r
+       return true;\r
+\r
+#endif // OS_WIN32\r
+}\r
+\r
+// 仮想 LAN カード列挙体の解放\r
+void CiFreeClientEnumVLan(RPC_CLIENT_ENUM_VLAN *e)\r
+{\r
+       UINT i;\r
+       // 引数チェック\r
+       if (e == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       for (i = 0;i < e->NumItem;i++)\r
+       {\r
+               Free(e->Items[i]);\r
+       }\r
+       Free(e->Items);\r
+}\r
+\r
+// 仮想 LAN カードに関する情報の設定\r
+bool CtSetVLan(CLIENT *c, RPC_CLIENT_SET_VLAN *set)\r
+{\r
+       // 引数チェック\r
+       if (c == NULL || set == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+#ifndef        OS_WIN32\r
+\r
+       LockList(c->UnixVLanList);\r
+       {\r
+               UNIX_VLAN t, *r;\r
+               Zero(&t, sizeof(t));\r
+               StrCpy(t.Name, sizeof(t.Name), set->DeviceName);\r
+\r
+               r = Search(c->UnixVLanList, &t);\r
+               if (r == NULL)\r
+               {\r
+                       // 存在しない\r
+                       CiSetError(c, ERR_VLAN_ALREADY_EXISTS);\r
+                       UnlockList(c->UnixVLanList);\r
+                       return false;\r
+               }\r
+\r
+               StrToMac(r->MacAddress, set->MacAddress);\r
+       }\r
+       UnlockList(c->UnixVLanList);\r
+\r
+       CiSaveConfigurationFile(c);\r
+       CiNotify(c);\r
+\r
+       return true;\r
+\r
+#else  // OS_WIN32\r
+\r
+       // 指定された名前の仮想 LAN カードが存在するかチェック\r
+       if (MsIsVLanExists(VLAN_ADAPTER_NAME_TAG, set->DeviceName) == false)\r
+       {\r
+               // 存在していない\r
+               CiSetError(c, ERR_OBJECT_NOT_FOUND);\r
+               return false;\r
+       }\r
+\r
+       // MAC アドレスの設定\r
+       MsSetMacAddress(VLAN_ADAPTER_NAME_TAG, set->DeviceName, set->MacAddress);\r
+\r
+       CiNotify(c);\r
+\r
+       return true;\r
+\r
+#endif // OS_WIN32\r
+}\r
+\r
+// 仮想 LAN カードに関する情報の取得\r
+bool CtGetVLan(CLIENT *c, RPC_CLIENT_GET_VLAN *get)\r
+{\r
+       char *tmp;\r
+       // 引数チェック\r
+       if (c == NULL || get == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+#ifndef        OS_WIN32\r
+\r
+       // サポートされていない\r
+       CiSetError(c, ERR_NOT_SUPPORTED);\r
+       return false;\r
+\r
+#else  // OS_WIN32\r
+\r
+       // 指定された名前の仮想 LAN カードが存在するかチェック\r
+       if (MsIsVLanExists(VLAN_ADAPTER_NAME_TAG, get->DeviceName) == false)\r
+       {\r
+               // 存在していない\r
+               CiSetError(c, ERR_OBJECT_NOT_FOUND);\r
+               return false;\r
+       }\r
+\r
+       // 動作状況\r
+       get->Enabled = MsIsVLanEnabled(get->DeviceName);\r
+\r
+       // MAC アドレス\r
+       tmp = MsGetMacAddress(VLAN_ADAPTER_NAME_TAG, get->DeviceName);\r
+       StrCpy(get->MacAddress, sizeof(get->MacAddress), tmp);\r
+       Free(tmp);\r
+\r
+       // バージョン\r
+       tmp = MsGetDriverVersion(VLAN_ADAPTER_NAME_TAG, get->DeviceName);\r
+       StrCpy(get->Version, sizeof(get->Version), tmp);\r
+       Free(tmp);\r
+\r
+       // ファイル名\r
+       tmp = MsGetDriverFileName(VLAN_ADAPTER_NAME_TAG, get->DeviceName);\r
+       StrCpy(get->FileName, sizeof(get->FileName), tmp);\r
+       Free(tmp);\r
+\r
+       // GUID\r
+       tmp = MsGetNetworkAdapterGuid(VLAN_ADAPTER_NAME_TAG, get->DeviceName);\r
+       StrCpy(get->Guid, sizeof(get->Guid), tmp);\r
+       Free(tmp);\r
+\r
+       return true;\r
+\r
+#endif // OS_WIN32\r
+}\r
+\r
+// 仮想 LAN カードのアップグレード\r
+bool CtUpgradeVLan(CLIENT *c, RPC_CLIENT_CREATE_VLAN *create)\r
+{\r
+#ifdef OS_WIN32\r
+       KAKUSHI *k = NULL;\r
+#endif // OS_WIN32\r
+\r
+       // 引数チェック\r
+       if (c == NULL || create == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+#ifndef        OS_WIN32\r
+\r
+       // 常に成功\r
+       return true;\r
+\r
+#else  // OS_WIN32\r
+\r
+       if (MsIsNt() == false)\r
+       {\r
+               // Win9x では不可\r
+               CiSetError(c, ERR_NOT_SUPPORTED);\r
+               return false;\r
+       }\r
+\r
+       // 指定された名前の LAN カードがすでに存在していないかどうかチェックする\r
+       if (MsIsVLanExists(VLAN_ADAPTER_NAME_TAG, create->DeviceName) == false)\r
+       {\r
+               // 存在していない\r
+               CiSetError(c, ERR_OBJECT_NOT_FOUND);\r
+               CiNotify(c);\r
+               return false;\r
+       }\r
+\r
+       if (MsIsVista() == false)\r
+       {\r
+               k = InitKakushi();      \r
+       }\r
+\r
+\r
+       if (MsIsVista() == false)\r
+       {\r
+               // インストールを行う (Windows Vista 以外)\r
+               if (MsUpgradeVLan(VLAN_ADAPTER_NAME_TAG,\r
+                       VLAN_CONNECTION_NAME,\r
+                       create->DeviceName) == false)\r
+               {\r
+                       // インストール失敗\r
+                       FreeKakushi(k);\r
+                       CiSetError(c, ERR_VLAN_INSTALL_ERROR);\r
+                       CiNotify(c);\r
+                       return false;\r
+               }\r
+       }\r
+       else\r
+       {\r
+               // インストールを行う (Windows Vista)\r
+               char tmp[MAX_SIZE];\r
+\r
+               Format(tmp, sizeof(tmp), "upgradevlan %s", create->DeviceName);\r
+\r
+               if (CncExecDriverInstaller(tmp) == false)\r
+               {\r
+                       // インストール失敗\r
+                       FreeKakushi(k);\r
+                       CiSetError(c, ERR_VLAN_INSTALL_ERROR);\r
+                       CiNotify(c);\r
+                       return false;\r
+               }\r
+       }\r
+\r
+       FreeKakushi(k);\r
+\r
+       CLog(c, "LC_UPDATE_VLAN", create->DeviceName);\r
+\r
+       CiNotify(c);\r
+\r
+       return true;\r
+\r
+#endif // OS_WIN32\r
+}\r
+\r
+// 仮想 LAN カードの作成\r
+bool CtCreateVLan(CLIENT *c, RPC_CLIENT_CREATE_VLAN *create)\r
+{\r
+       TOKEN_LIST *t;\r
+       UINT max_len;\r
+\r
+#ifdef OS_WIN32\r
+       KAKUSHI *k = NULL;\r
+#endif // OS_WIN32\r
+\r
+       // 引数チェック\r
+       if (c == NULL || create == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+#ifndef        OS_WIN32\r
+\r
+       // Win32 以外\r
+       if (GetOsInfo()->OsType == OSTYPE_MACOS_X)\r
+       {\r
+               // MacOS X では仮想 LAN カードは増減できない\r
+               CiSetError(c, ERR_NOT_SUPPORTED);\r
+               return false;\r
+       }\r
+\r
+       // 指定された名前が有効かどうかチェックする\r
+       if (IsSafeStr(create->DeviceName) == false)\r
+       {\r
+               // 名前が不正\r
+               CiSetError(c, ERR_VLAN_INVALID_NAME);\r
+               return false;\r
+       }\r
+\r
+       // 指定した名前の LAN カードがすでに存在していないかどうかチェックする\r
+       LockList(c->UnixVLanList);\r
+       {\r
+               UNIX_VLAN t, *r;\r
+               Zero(&t, sizeof(t));\r
+               StrCpy(t.Name, sizeof(t.Name), create->DeviceName);\r
+\r
+               r = Search(c->UnixVLanList, &t);\r
+               if (r != NULL)\r
+               {\r
+                       // すでに存在している\r
+                       CiSetError(c, ERR_VLAN_ALREADY_EXISTS);\r
+                       UnlockList(c->UnixVLanList);\r
+                       return false;\r
+               }\r
+\r
+               // 登録する\r
+               r = ZeroMalloc(sizeof(UNIX_VLAN));\r
+               r->Enabled = true;\r
+               GenMacAddress(r->MacAddress);\r
+               StrCpy(r->Name, sizeof(r->Name), create->DeviceName);\r
+\r
+               // tap 作成\r
+               if (UnixVLanCreate(r->Name, r->MacAddress) == false)\r
+               {\r
+                       // 失敗\r
+                       Free(r);\r
+                       CiSetError(c, ERR_VLAN_INSTALL_ERROR);\r
+                       UnlockList(c->UnixVLanList);\r
+                       return false;\r
+               }\r
+\r
+               CLog(c, "LC_CREATE_VLAN", create->DeviceName);\r
+\r
+               Add(c->UnixVLanList, r);\r
+       }\r
+       UnlockList(c->UnixVLanList);\r
+\r
+       CiNormalizeAccountVLan(c);\r
+\r
+       CiNotify(c);\r
+       CiSaveConfigurationFile(c);\r
+\r
+       return true;\r
+\r
+#else  // OS_WIN32\r
+\r
+       if (OS_IS_WINDOWS_9X(GetOsInfo()->OsType))\r
+       {\r
+               // Win9x では LAN カードは 1 個しか作成できない\r
+               TOKEN_LIST *t;\r
+\r
+               t = MsEnumNetworkAdapters(VLAN_ADAPTER_NAME, "---dummy-string-ut--");\r
+               if (t != NULL)\r
+               {\r
+                       if (t->NumTokens >= 1)\r
+                       {\r
+                               FreeToken(t);\r
+                               CiSetError(c, ERR_NOT_SUPPORTED);\r
+                               return false;\r
+                       }\r
+                       FreeToken(t);\r
+               }\r
+       }\r
+\r
+       // 指定された名前が有効かどうかチェックする\r
+       if (IsSafeStr(create->DeviceName) == false)\r
+       {\r
+               // 名前が不正\r
+               CiSetError(c, ERR_VLAN_INVALID_NAME);\r
+               return false;\r
+       }\r
+\r
+       max_len = MsIsNt() ? MAX_DEVICE_NAME_LEN : MAX_DEVICE_NAME_LEN_9X;\r
+       if (StrLen(create->DeviceName) > max_len)\r
+       {\r
+               // 名前が長すぎる\r
+               CiSetError(c, ERR_VLAN_INVALID_NAME);\r
+               return false;\r
+       }\r
+\r
+       // 指定された名前の LAN カードがすでに存在していないかどうかチェックする\r
+       if (MsIsVLanExists(VLAN_ADAPTER_NAME_TAG, create->DeviceName))\r
+       {\r
+               // すでに存在している\r
+               CiSetError(c, ERR_VLAN_ALREADY_EXISTS);\r
+               return false;\r
+       }\r
+\r
+       if (MsIsNt())\r
+       {\r
+               if (MsIsVista() == false)\r
+               {\r
+                       k = InitKakushi();\r
+               }\r
+       }\r
+\r
+       if (MsIsVista() == false)\r
+       {\r
+               // インストールを行う (Windows Vista 以外)\r
+               if (MsInstallVLan(VLAN_ADAPTER_NAME_TAG, VLAN_CONNECTION_NAME, create->DeviceName) == false)\r
+               {\r
+                       // インストール失敗\r
+                       FreeKakushi(k);\r
+                       CiSetError(c, ERR_VLAN_INSTALL_ERROR);\r
+                       CiNotify(c);\r
+                       return false;\r
+               }\r
+       }\r
+       else\r
+       {\r
+               // インストールを行う (Windows Vista)\r
+               char tmp[MAX_SIZE];\r
+\r
+               Format(tmp, sizeof(tmp), "instvlan %s", create->DeviceName);\r
+\r
+               if (CncExecDriverInstaller(tmp) == false)\r
+               {\r
+                       // インストール失敗\r
+                       FreeKakushi(k);\r
+                       CiSetError(c, ERR_VLAN_INSTALL_ERROR);\r
+                       CiNotify(c);\r
+                       return false;\r
+               }\r
+       }\r
+\r
+       FreeKakushi(k);\r
+\r
+       t = MsEnumNetworkAdapters(VLAN_ADAPTER_NAME, "---dummy-string-ut--");\r
+       if (t->NumTokens == 1)\r
+       {\r
+               UINT i;\r
+               // インストールを行った結果、仮想 LAN カードが 1 つになった場合は\r
+               // 既存のすべてのアカウントの仮想 LAN カードをこの仮想 LAN カードにセットする\r
+               LockList(c->AccountList);\r
+               {\r
+                       for (i = 0;i < LIST_NUM(c->AccountList);i++)\r
+                       {\r
+                               ACCOUNT *a = LIST_DATA(c->AccountList, i);\r
+                               Lock(a->lock);\r
+                               {\r
+                                       if (a->ClientOption != NULL)\r
+                                       {\r
+                                               StrCpy(a->ClientOption->DeviceName, sizeof(a->ClientOption->DeviceName), create->DeviceName);\r
+                                       }\r
+                               }\r
+                               Unlock(a->lock);\r
+                       }\r
+               }\r
+               UnlockList(c->AccountList);\r
+       }\r
+       FreeToken(t);\r
+\r
+       CLog(c, "LC_CREATE_VLAN", create->DeviceName);\r
+\r
+       CiNormalizeAccountVLan(c);\r
+\r
+       CiNotify(c);\r
+\r
+       CiSaveConfigurationFile(c);\r
+\r
+       if (MsIsNt() == false)\r
+       {\r
+               if (GetOsInfo()->OsType == OSTYPE_WINDOWS_ME)\r
+               {\r
+                       // Windows Me の場合は警告表示\r
+                       MsgBox(NULL, 0x00000040L, _UU("CM_9X_VLAN_ME_MESSAGE"));\r
+               }\r
+\r
+               ReleaseThread(NewThread(Win9xRebootThread, NULL));\r
+       }\r
+\r
+       return true;\r
+\r
+#endif // OS_WIN32\r
+}\r
+\r
+// セキュアデバイス内のオブジェクト列挙\r
+bool CtEnumObjectInSecure(CLIENT *c, RPC_ENUM_OBJECT_IN_SECURE *e)\r
+{\r
+       UINT i;\r
+       // 引数チェック\r
+       if (c == NULL || e == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       e->NumItem = 5;\r
+       e->ItemName = ZeroMalloc(sizeof(char *) * e->NumItem);\r
+       e->ItemType = ZeroMalloc(sizeof(bool) * e->NumItem);\r
+\r
+       for (i = 0;i < e->NumItem;i++)\r
+       {\r
+               char tmp[MAX_SIZE];\r
+               Format(tmp, sizeof(tmp), "Test Object %u", i);\r
+               e->ItemName[i] = CopyStr(tmp);\r
+               e->ItemType[i] = (i % 2 == 0) ? false : true;\r
+       }\r
+\r
+       return true;\r
+}\r
+\r
+// 使用するセキュアデバイスの取得\r
+bool CtGetUseSecure(CLIENT *c, RPC_USE_SECURE *sec)\r
+{\r
+       // 引数チェック\r
+       if (c == NULL || sec == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       sec->DeviceId = c->UseSecureDeviceId;\r
+\r
+       return true;\r
+}\r
+\r
+// 使用するセキュアデバイスの指定\r
+bool CtUseSecure(CLIENT *c, RPC_USE_SECURE *sec)\r
+{\r
+       // 引数チェック\r
+       if (c == NULL || sec == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+// クライアントマネージャに指定されたデバイスが存在するかどうかチェックしない\r
+/*     if (CheckSecureDeviceId(sec->DeviceId))\r
+       {\r
+               c->UseSecureDeviceId = sec->DeviceId;\r
+       }\r
+       else\r
+       {\r
+               CiSetError(c, ERR_OBJECT_NOT_FOUND);\r
+               return false;\r
+       }\r
+*/\r
+       c->UseSecureDeviceId = sec->DeviceId;\r
+\r
+       CiSaveConfigurationFile(c);\r
+\r
+       return true;\r
+}\r
+\r
+// セキュアデバイスの列挙\r
+bool CtEnumSecure(CLIENT *c, RPC_CLIENT_ENUM_SECURE *e)\r
+{\r
+       LIST *o;\r
+       UINT i;\r
+       // 引数チェック\r
+       if (c == NULL || e == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       o = GetSecureDeviceList();\r
+\r
+       e->NumItem = LIST_NUM(o);\r
+       e->Items = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_SECURE_ITEM *) * e->NumItem);\r
+\r
+       for (i = 0;i < LIST_NUM(o);i++)\r
+       {\r
+               RPC_CLIENT_ENUM_SECURE_ITEM *item = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_SECURE_ITEM));\r
+               SECURE_DEVICE *s = LIST_DATA(o, i);\r
+\r
+               item->DeviceId = s->Id;\r
+               StrCpy(item->DeviceName, sizeof(item->DeviceName), s->DeviceName);\r
+               StrCpy(item->Manufacturer, sizeof(item->Manufacturer), s->Manufacturer);\r
+               item->Type = s->Type;\r
+\r
+               e->Items[i] = item;\r
+       }\r
+\r
+       return true;\r
+}\r
+\r
+// セキュアデバイス列挙体の解放\r
+void CiFreeClientEnumSecure(RPC_CLIENT_ENUM_SECURE *e)\r
+{\r
+       UINT i;\r
+       // 引数チェック\r
+       if (e == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       for (i = 0;i < e->NumItem;i++)\r
+       {\r
+               Free(e->Items[i]);\r
+       }\r
+       Free(e->Items);\r
+}\r
+\r
+// RPC_GET_ISSUER の解放\r
+void CiFreeGetIssuer(RPC_GET_ISSUER *a)\r
+{\r
+       // 引数チェック\r
+       if (a == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       if (a->issuer_x != NULL)\r
+       {\r
+               FreeX(a->issuer_x);\r
+       }\r
+       if (a->x != NULL)\r
+       {\r
+               FreeX(a->x);\r
+       }\r
+}\r
+\r
+// 署名者の取得\r
+bool CtGetIssuer(CLIENT *c, RPC_GET_ISSUER *a)\r
+{\r
+       X *x;\r
+       // 引数チェック\r
+       if (c == NULL || a == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       x = FindCaSignedX(c->Cedar->CaList, a->x);\r
+       if (x == NULL)\r
+       {\r
+               CiSetError(c, ERR_OBJECT_NOT_FOUND);;\r
+               return false;\r
+       }\r
+       else\r
+       {\r
+               a->issuer_x = x;\r
+               if (a->x != NULL)\r
+               {\r
+                       FreeX(a->x);\r
+                       a->x = NULL;\r
+               }\r
+               return true;\r
+       }\r
+}\r
+\r
+// CA 証明書の取得\r
+bool CtGetCa(CLIENT *c, RPC_GET_CA *get)\r
+{\r
+       bool ret = true;\r
+       X *cert = NULL;\r
+       // 引数チェック\r
+       if (c == NULL || get == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       LockList(c->Cedar->CaList);\r
+       {\r
+               UINT i;\r
+\r
+               for (i = 0;i < LIST_NUM(c->Cedar->CaList);i++)\r
+               {\r
+                       X *x = LIST_DATA(c->Cedar->CaList, i);\r
+\r
+                       if (POINTER_TO_KEY(x) == get->Key)\r
+                       {\r
+                               cert = CloneX(x);\r
+                               break;\r
+                       }\r
+               }\r
+       }\r
+       UnlockList(c->Cedar->CaList);\r
+\r
+       if (cert == NULL)\r
+       {\r
+               // 証明書は存在しない\r
+               ret = false;\r
+               CiSetError(c, ERR_OBJECT_NOT_FOUND);\r
+       }\r
+       else\r
+       {\r
+               ret = true;\r
+               get->x = cert;\r
+       }\r
+\r
+       return ret;\r
+}\r
+\r
+// CA 証明書の削除\r
+bool CtDeleteCa(CLIENT *c, RPC_CLIENT_DELETE_CA *p)\r
+{\r
+       bool ret;\r
+       // 引数チェック\r
+       if (c == NULL || p == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       ret = DeleteCa(c->Cedar, p->Key);\r
+\r
+       if (ret == false)\r
+       {\r
+               CiSetError(c, ERR_OBJECT_NOT_FOUND);\r
+       }\r
+\r
+       CiSaveConfigurationFile(c);\r
+\r
+       return ret;\r
+}\r
+\r
+// CA 証明書の追加\r
+bool CtAddCa(CLIENT *c, RPC_CERT *cert)\r
+{\r
+       // 引数チェック\r
+       if (c == NULL || cert == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       if (cert->x->is_compatible_bit == false)\r
+       {\r
+               CiSetError(c, ERR_NOT_RSA_1024);\r
+               return false;\r
+       }\r
+\r
+       AddCa(c->Cedar, cert->x);\r
+\r
+       CiSaveConfigurationFile(c);\r
+\r
+       return true;\r
+}\r
+\r
+// 信頼する CA の列挙\r
+bool CtEnumCa(CLIENT *c, RPC_CLIENT_ENUM_CA *e)\r
+{\r
+       // 引数チェック\r
+       if (c == NULL || e == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       Zero(e, sizeof(RPC_CLIENT_ENUM_CA));\r
+\r
+       LockList(c->Cedar->CaList);\r
+       {\r
+               UINT i;\r
+               e->NumItem = LIST_NUM(c->Cedar->CaList);\r
+               e->Items = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_CA_ITEM *) * e->NumItem);\r
+\r
+               for (i = 0;i < e->NumItem;i++)\r
+               {\r
+                       X *x = LIST_DATA(c->Cedar->CaList, i);\r
+                       e->Items[i] = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_CA_ITEM));\r
+                       GetAllNameFromNameEx(e->Items[i]->SubjectName, sizeof(e->Items[i]->SubjectName), x->subject_name);\r
+                       GetAllNameFromNameEx(e->Items[i]->IssuerName, sizeof(e->Items[i]->IssuerName), x->issuer_name);\r
+                       e->Items[i]->Expires = x->notAfter;\r
+                       e->Items[i]->Key = POINTER_TO_KEY(x);\r
+               }\r
+       }\r
+       UnlockList(c->Cedar->CaList);\r
+\r
+       return true;\r
+}\r
+\r
+// CA 列挙体を解放する\r
+void CiFreeClientEnumCa(RPC_CLIENT_ENUM_CA *e)\r
+{\r
+       UINT i;\r
+       // 引数チェック\r
+       if (e == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       for (i = 0;i < e->NumItem;i++)\r
+       {\r
+               RPC_CLIENT_ENUM_CA_ITEM *ca = e->Items[i];\r
+               Free(ca);\r
+       }\r
+       Free(e->Items);\r
+}\r
+\r
+// パスワードの設定の取得\r
+bool CtGetPasswordSetting(CLIENT *c, RPC_CLIENT_PASSWORD_SETTING *a)\r
+{\r
+       UCHAR hash[SHA1_SIZE];\r
+       // 引数チェック\r
+       if (c == NULL || a == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       Hash(hash, "", 0, true);\r
+       if (Cmp(hash, c->EncryptedPassword, SHA1_SIZE) == 0)\r
+       {\r
+               a->IsPasswordPresented = false;\r
+       }\r
+       else\r
+       {\r
+               a->IsPasswordPresented = true;\r
+       }\r
+\r
+       a->PasswordRemoteOnly = c->PasswordRemoteOnly;\r
+\r
+       return true;\r
+}\r
+\r
+// パスワードの設定\r
+bool CtSetPassword(CLIENT *c, RPC_CLIENT_PASSWORD *pass)\r
+{\r
+       char *str;\r
+       if (c == NULL)\r
+       {\r
+               return false;\r
+       }\r
+       if (pass->Password == NULL)\r
+       {\r
+               str = "";\r
+       }\r
+       else\r
+       {\r
+               str = pass->Password;\r
+       }\r
+\r
+       if (StrCmp(str, "********") != 0)\r
+       {\r
+               // パスワードのハッシュ\r
+               Hash(c->EncryptedPassword, str, StrLen(str), true);\r
+       }\r
+\r
+       c->PasswordRemoteOnly = pass->PasswordRemoteOnly;\r
+\r
+       CLog(c, "LC_SET_PASSWORD");\r
+\r
+       CiSaveConfigurationFile(c);\r
+\r
+       return true;\r
+}\r
+\r
+// クライアントエラーコードの設定\r
+void CiSetError(CLIENT *c, UINT err)\r
+{\r
+       // 引数チェック\r
+       if (c == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       c->Err = err;\r
+}\r
+\r
+// UNIX 仮想 LAN カード比較関数\r
+int CiCompareUnixVLan(void *p1, void *p2)\r
+{\r
+       UNIX_VLAN *v1, *v2;\r
+       if (p1 == NULL || p2 == NULL)\r
+       {\r
+               return 0;\r
+       }\r
+       v1 = *(UNIX_VLAN **)p1;\r
+       v2 = *(UNIX_VLAN **)p2;\r
+       if (v1 == NULL || v2 == NULL)\r
+       {\r
+               return 0;\r
+       }\r
+\r
+       return StrCmpi(v1->Name, v2->Name);\r
+}\r
+\r
+// 不正な VLAN 名が指定されているアカウントの設定を修正する\r
+void CiNormalizeAccountVLan(CLIENT *c)\r
+{\r
+       bool b = false;\r
+       char *name;\r
+       UINT i;\r
+       // 引数チェック\r
+       if (c == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       name = CiGetFirstVLan(c);\r
+\r
+       if (name != NULL)\r
+       {\r
+               LockList(c->AccountList);\r
+               {\r
+                       for (i = 0;i < LIST_NUM(c->AccountList);i++)\r
+                       {\r
+                               ACCOUNT *a = LIST_DATA(c->AccountList, i);\r
+\r
+                               Lock(a->lock);\r
+                               {\r
+                                       if (a->ClientOption != NULL)\r
+                                       {\r
+                                               if (CiIsVLan(c, a->ClientOption->DeviceName) == false)\r
+                                               {\r
+                                                       StrCpy(a->ClientOption->DeviceName, sizeof(a->ClientOption->DeviceName),\r
+                                                               name);\r
+                                                       b = true;\r
+                                               }\r
+                                       }\r
+                               }\r
+                               Unlock(a->lock);\r
+                       }\r
+               }\r
+               UnlockList(c->AccountList);\r
+\r
+               Free(name);\r
+       }\r
+\r
+       if (b)\r
+       {\r
+               CiNotify(c);\r
+               CiSaveConfigurationFile(c);\r
+       }\r
+}\r
+\r
+// 指定した名前の仮想 LAN カードが存在しているかどうか調べる\r
+bool CiIsVLan(CLIENT *c, char *name)\r
+{\r
+       // 引数チェック\r
+       if (c == NULL || name == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+#ifdef OS_WIN32\r
+       {\r
+               TOKEN_LIST *t;\r
+               UINT i;\r
+\r
+               t = MsEnumNetworkAdapters(VLAN_ADAPTER_NAME, "---dummy-string-ut--");\r
+               if (t == NULL)\r
+               {\r
+                       return false;\r
+               }\r
+\r
+               for (i = 0;i < t->NumTokens;i++)\r
+               {\r
+                       if (StrCmpi(t->Token[i], name) == 0)\r
+                       {\r
+                               FreeToken(t);\r
+                               return true;\r
+                       }\r
+               }\r
+\r
+               FreeToken(t);\r
+\r
+               return false;\r
+       }\r
+#else  // OS_WIN32\r
+       {\r
+               UNIX_VLAN *v;\r
+               UINT i;\r
+               bool ret = false;\r
+\r
+               LockList(c->UnixVLanList);\r
+               {\r
+                       for (i = 0;i < LIST_NUM(c->UnixVLanList);i++)\r
+                       {\r
+                               v = (UNIX_VLAN *)LIST_DATA(c->UnixVLanList, i);\r
+                               if (StrCmpi(v->Name, name) == 0)\r
+                               {\r
+                                       ret = true;\r
+                               }\r
+                       }\r
+               }\r
+               UnlockList(c->UnixVLanList);\r
+\r
+               return ret;\r
+       }\r
+#endif // OS_WIN32\r
+}\r
+\r
+// すべての接続アカウントにおいて、存在しない仮想 LAN カードが指定されている場合で\r
+// 現在の仮想 LAN カードが 1 枚だけの場合は、その仮想 LAN カードに指定しなおす\r
+void CiSetVLanToDefault(CLIENT *c)\r
+{\r
+       char device_name[MAX_SIZE];\r
+       // 引数チェック\r
+       if (c == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+#ifdef OS_WIN32\r
+       {\r
+               TOKEN_LIST *t;\r
+\r
+               t = MsEnumNetworkAdapters(VLAN_ADAPTER_NAME, "---dummy-string-ut--");\r
+               if (t == NULL)\r
+               {\r
+                       return;\r
+               }\r
+               if (t->NumTokens != 1)\r
+               {\r
+                       FreeToken(t);\r
+                       return;\r
+               }\r
+               StrCpy(device_name, sizeof(device_name), t->Token[0]);\r
+               FreeToken(t);\r
+       }\r
+#else  // OS_WIN32\r
+       {\r
+               UINT i;\r
+               UNIX_VLAN *v;\r
+\r
+               LockList(c->UnixVLanList);\r
+\r
+               if (LIST_NUM(c->UnixVLanList) != 1)\r
+               {\r
+                       UnlockList(c->UnixVLanList);\r
+                       return;\r
+               }\r
+               v = LIST_DATA(c->UnixVLanList, 0);\r
+               StrCpy(device_name, sizeof(device_name), v->Name);\r
+\r
+               UnlockList(c->UnixVLanList);\r
+       }\r
+#endif // OS_WIN32\r
+\r
+       {\r
+               UINT i;\r
+               LockList(c->AccountList);\r
+               {\r
+                       for (i = 0;i < LIST_NUM(c->AccountList);i++)\r
+                       {\r
+                               ACCOUNT *a = LIST_DATA(c->AccountList, i);\r
+\r
+                               Lock(a->lock);\r
+                               {\r
+                                       if (CiIsVLan(c, a->ClientOption->DeviceName) == false)\r
+                                       {\r
+                                               StrCpy(a->ClientOption->DeviceName, sizeof(a->ClientOption->DeviceName),\r
+                                                       device_name);\r
+                                       }\r
+                               }\r
+                               Unlock(a->lock);\r
+                       }\r
+               }\r
+               UnlockList(c->AccountList);\r
+       }\r
+}\r
+\r
+// 設定の初期化\r
+void CiInitConfiguration(CLIENT *c)\r
+{\r
+       // 引数チェック\r
+       if (c == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+#ifdef OS_UNIX\r
+       // VLAN 初期化\r
+       UnixVLanInit();\r
+#endif  // OS_UNIX\r
+\r
+       // アカウントリスト\r
+       c->AccountList = NewList(CiCompareAccount);\r
+\r
+       // Unix 版 VLAN リスト\r
+       if (OS_IS_UNIX(GetOsInfo()->OsType))\r
+       {\r
+               c->UnixVLanList = NewList(CiCompareUnixVLan);\r
+       }\r
+\r
+       // 設定ファイルの読み込み\r
+       CLog(c, "LC_LOAD_CONFIG_1");\r
+       if (CiLoadConfigurationFile(c) == false)\r
+       {\r
+               CLog(c, "LC_LOAD_CONFIG_3");\r
+               // 設定ファイルが存在しないので初期設定を行う\r
+               // パスワードを空にする\r
+               Hash(c->EncryptedPassword, "", 0, true);\r
+               // クライアント設定を初期化\r
+               if (OS_IS_WINDOWS(GetOsInfo()->OsType))\r
+               {\r
+                       // Windows の場合はリモートを禁止\r
+                       c->Config.AllowRemoteConfig = false;\r
+               }\r
+               else\r
+               {\r
+                       // UNIX の場合もリモートを禁止\r
+                       c->Config.AllowRemoteConfig = false;\r
+               }\r
+               StrCpy(c->Config.KeepConnectHost, sizeof(c->Config.KeepConnectHost), CLIENT_DEFAULT_KEEPALIVE_HOST);\r
+               c->Config.KeepConnectPort = CLIENT_DEFAULT_KEEPALIVE_PORT;\r
+               c->Config.KeepConnectProtocol = CONNECTION_UDP;\r
+               c->Config.KeepConnectInterval = CLIENT_DEFAULT_KEEPALIVE_INTERVAL;\r
+               c->Config.UseKeepConnect = false;       // Client ではデフォルトでは接続維持機能を使用しない\r
+               // 自動ファイル削除器\r
+               c->Eraser = NewEraser(c->Logger, 0);\r
+       }\r
+       else\r
+       {\r
+               CLog(c, "LC_LOAD_CONFIG_2");\r
+       }\r
+\r
+       // 仮想 LAN カードの適切な設定\r
+       CiSetVLanToDefault(c);\r
+}\r
+\r
+// 設定の解放\r
+void CiFreeConfiguration(CLIENT *c)\r
+{\r
+       UINT i;\r
+       // 引数チェック\r
+       if (c == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       // 設定ファイルへ書き込み\r
+       CiSaveConfigurationFile(c);\r
+\r
+       // 設定ファイル解放\r
+       FreeCfgRw(c->CfgRw);\r
+\r
+       // アカウントリストの解放\r
+       for (i = 0;i < LIST_NUM(c->AccountList);i++)\r
+       {\r
+               ACCOUNT *a = LIST_DATA(c->AccountList, i);\r
+\r
+               CiFreeAccount(a);\r
+       }\r
+       ReleaseList(c->AccountList);\r
+\r
+       if (c->UnixVLanList != NULL)\r
+       {\r
+               // UNIX 版 VLAN リストの解放\r
+               for (i = 0;i < LIST_NUM(c->UnixVLanList);i++)\r
+               {\r
+                       UNIX_VLAN *v = LIST_DATA(c->UnixVLanList, i);\r
+                       Free(v);\r
+               }\r
+               ReleaseList(c->UnixVLanList);\r
+       }\r
+       c->UnixVLanList = NULL;\r
+\r
+#ifdef OS_UNIX\r
+       // VLAN 解放\r
+       UnixVLanFree();\r
+#endif // OS_UNIX\r
+}\r
+\r
+// 証明書取得データの解放\r
+void CiFreeGetCa(RPC_GET_CA *a)\r
+{\r
+       // 引数チェック\r
+       if (a == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       FreeX(a->x);\r
+}\r
+\r
+// クライアント認証データの解放\r
+void CiFreeClientAuth(CLIENT_AUTH *auth)\r
+{\r
+       // 引数チェック\r
+       if (auth == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       if (auth->ClientX != NULL)\r
+       {\r
+               FreeX(auth->ClientX);\r
+       }\r
+       if (auth->ClientK != NULL)\r
+       {\r
+               FreeK(auth->ClientK);\r
+       }\r
+\r
+       Free(auth);\r
+}\r
+\r
+// アカウントの解放\r
+void CiFreeAccount(ACCOUNT *a)\r
+{\r
+       // 引数チェック\r
+       if (a == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       // ロック解放\r
+       DeleteLock(a->lock);\r
+\r
+       // クライアントオプションの解放\r
+       Free(a->ClientOption);\r
+\r
+       // クライアント認証データの解放\r
+       CiFreeClientAuth(a->ClientAuth);\r
+\r
+       if (a->ServerCert != NULL)\r
+       {\r
+               FreeX(a->ServerCert);\r
+       }\r
+\r
+       Free(a);\r
+}\r
+\r
+// アカウントのソート\r
+int CiCompareAccount(void *p1, void *p2)\r
+{\r
+       ACCOUNT *a1, *a2;\r
+       if (p1 == NULL || p2 == NULL)\r
+       {\r
+               return 0;\r
+       }\r
+       a1 = *(ACCOUNT **)p1;\r
+       a2 = *(ACCOUNT **)p2;\r
+       if (a1 == NULL || a2 == NULL)\r
+       {\r
+               return 0;\r
+       }\r
+\r
+       return UniStrCmpi(a1->ClientOption->AccountName, a2->ClientOption->AccountName);\r
+}\r
+\r
+// クライアントコンフィグレーションの読み込み\r
+void CiLoadClientConfig(CLIENT_CONFIG *c, FOLDER *f)\r
+{\r
+       // 引数チェック\r
+       if (c == NULL || f == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       c->UseKeepConnect = CfgGetBool(f, "UseKeepConnect");\r
+       CfgGetStr(f, "KeepConnectHost", c->KeepConnectHost, sizeof(c->KeepConnectHost));\r
+       c->KeepConnectPort = CfgGetInt(f, "KeepConnectPort");\r
+       c->KeepConnectProtocol = CfgGetInt(f, "KeepConnectProtocol");\r
+       c->AllowRemoteConfig = CfgGetBool(f, "AllowRemoteConfig");\r
+       c->KeepConnectInterval = MAKESURE(CfgGetInt(f, "KeepConnectInterval"), KEEP_INTERVAL_MIN, KEEP_INTERVAL_MAX);\r
+}\r
+\r
+// クライアント認証データの読み込み\r
+CLIENT_AUTH *CiLoadClientAuth(FOLDER *f)\r
+{\r
+       CLIENT_AUTH *a;\r
+       char *s;\r
+       BUF *b;\r
+       // 引数チェック\r
+       if (f == NULL)\r
+       {\r
+               return NULL;\r
+       }\r
+\r
+       a = ZeroMalloc(sizeof(CLIENT_AUTH));\r
+\r
+       a->AuthType = CfgGetInt(f, "AuthType");\r
+       CfgGetStr(f, "Username", a->Username, sizeof(a->Username));\r
+\r
+       switch (a->AuthType)\r
+       {\r
+       case CLIENT_AUTHTYPE_ANONYMOUS:\r
+               break;\r
+\r
+       case CLIENT_AUTHTYPE_PASSWORD:\r
+               CfgGetByte(f, "HashedPassword", a->HashedPassword, SHA1_SIZE);\r
+               break;\r
+\r
+       case CLIENT_AUTHTYPE_PLAIN_PASSWORD:\r
+               b = CfgGetBuf(f, "EncryptedPassword");\r
+               if (b != NULL)\r
+               {\r
+                       s = DecryptPassword(b);\r
+                       StrCpy(a->PlainPassword, sizeof(a->PlainPassword), s);\r
+                       Free(s);\r
+                       FreeBuf(b);\r
+               }\r
+               break;\r
+\r
+       case CLIENT_AUTHTYPE_CERT:\r
+               b = CfgGetBuf(f, "ClientCert");\r
+               if (b != NULL)\r
+               {\r
+                       a->ClientX = BufToX(b, false);\r
+               }\r
+               FreeBuf(b);\r
+               b = CfgGetBuf(f, "ClientKey");\r
+               if (b != NULL)\r
+               {\r
+                       a->ClientK = BufToK(b, true, false, NULL);\r
+               }\r
+               FreeBuf(b);\r
+               break;\r
+\r
+       case CLIENT_AUTHTYPE_SECURE:\r
+               CfgGetStr(f, "SecurePublicCertName", a->SecurePublicCertName, sizeof(a->SecurePublicCertName));\r
+               CfgGetStr(f, "SecurePrivateKeyName", a->SecurePrivateKeyName, sizeof(a->SecurePrivateKeyName));\r
+               break;\r
+       }\r
+\r
+       return a;\r
+}\r
+\r
+// クライアントオプションの読み込み\r
+CLIENT_OPTION *CiLoadClientOption(FOLDER *f)\r
+{\r
+       CLIENT_OPTION *o;\r
+       char *s;\r
+       BUF *b;\r
+       // 引数チェック\r
+       if (f == NULL)\r
+       {\r
+               return NULL;\r
+       }\r
+\r
+       o = ZeroMalloc(sizeof(CLIENT_OPTION));\r
+\r
+       CfgGetUniStr(f, "AccountName", o->AccountName, sizeof(o->AccountName));\r
+       CfgGetStr(f, "Hostname", o->Hostname, sizeof(o->Hostname));\r
+       o->Port = CfgGetInt(f, "Port");\r
+       o->PortUDP = CfgGetInt(f, "PortUDP");\r
+       o->ProxyType = CfgGetInt(f, "ProxyType");\r
+       CfgGetStr(f, "ProxyName", o->ProxyName, sizeof(o->ProxyName));\r
+       o->ProxyPort = CfgGetInt(f, "ProxyPort");\r
+       CfgGetStr(f, "ProxyUsername", o->ProxyUsername, sizeof(o->ProxyUsername));\r
+       b = CfgGetBuf(f, "ProxyPassword");\r
+       s = DecryptPassword(b);\r
+       StrCpy(o->ProxyPassword, sizeof(o->ProxyPassword), s);\r
+       Free(s);\r
+       FreeBuf(b);\r
+       o->NumRetry = CfgGetInt(f, "NumRetry");\r
+       o->RetryInterval = CfgGetInt(f, "RetryInterval");\r
+       CfgGetStr(f, "HubName", o->HubName, sizeof(o->HubName));\r
+       o->MaxConnection = CfgGetInt(f, "MaxConnection");\r
+       o->UseEncrypt = CfgGetBool(f, "UseEncrypt");\r
+       o->UseCompress = CfgGetBool(f, "UseCompress");\r
+       o->HalfConnection = CfgGetBool(f, "HalfConnection");\r
+       o->NoRoutingTracking = CfgGetBool(f, "NoRoutingTracking");\r
+       CfgGetStr(f, "DeviceName", o->DeviceName, sizeof(o->DeviceName));\r
+       o->AdditionalConnectionInterval = CfgGetInt(f, "AdditionalConnectionInterval");\r
+       o->HideStatusWindow = CfgGetBool(f, "HideStatusWindow");\r
+       o->HideNicInfoWindow = CfgGetBool(f, "HideNicInfoWindow");\r
+       o->ConnectionDisconnectSpan = CfgGetInt(f, "ConnectionDisconnectSpan");\r
+       o->RequireMonitorMode = CfgGetBool(f, "RequireMonitorMode");\r
+       o->RequireBridgeRoutingMode = CfgGetBool(f, "RequireBridgeRoutingMode");\r
+       o->DisableQoS = CfgGetBool(f, "DisableQoS");\r
+       o->FromAdminPack = CfgGetBool(f, "FromAdminPack");\r
+       o->NoTls1 = CfgGetBool(f, "NoTls1");\r
+\r
+       return o;\r
+}\r
+\r
+// アカウントデータの読み込み\r
+ACCOUNT *CiLoadClientAccount(FOLDER *f)\r
+{\r
+       ACCOUNT *a;\r
+       FOLDER *client_option_folder, *client_auth_folder;\r
+       BUF *b;\r
+       char tmp[64];\r
+       // 引数チェック\r
+       if (f == NULL)\r
+       {\r
+               return NULL;\r
+       }\r
+\r
+       client_option_folder = CfgGetFolder(f, "ClientOption");\r
+\r
+       if (client_option_folder != NULL)\r
+       {\r
+               // すでに登録されているアカウント名と一致するかどうか比較する\r
+       }\r
+\r
+       client_auth_folder = CfgGetFolder(f, "ClientAuth");\r
+\r
+       if (client_option_folder == NULL || client_auth_folder == NULL)\r
+       {\r
+               return NULL;\r
+       }\r
+\r
+       a = ZeroMalloc(sizeof(ACCOUNT));\r
+       a->lock = NewLock();\r
+\r
+       a->ClientOption = CiLoadClientOption(client_option_folder);\r
+       a->ClientAuth = CiLoadClientAuth(client_auth_folder);\r
+\r
+       a->StartupAccount = CfgGetBool(f, "StartupAccount");\r
+       a->CheckServerCert = CfgGetBool(f, "CheckServerCert");\r
+       a->CreateDateTime = CfgGetInt64(f, "CreateDateTime");\r
+       a->UpdateDateTime = CfgGetInt64(f, "UpdateDateTime");\r
+       a->LastConnectDateTime = CfgGetInt64(f, "LastConnectDateTime");\r
+\r
+       b = CfgGetBuf(f, "ServerCert");\r
+       if (b != NULL)\r
+       {\r
+               a->ServerCert = BufToX(b, false);\r
+               FreeBuf(b);\r
+       }\r
+\r
+       if (CfgGetStr(f, "ShortcutKey", tmp, sizeof(tmp)))\r
+       {\r
+               BUF *b = StrToBin(tmp);\r
+               if (b->Size == SHA1_SIZE)\r
+               {\r
+                       Copy(a->ShortcutKey, b->Buf, SHA1_SIZE);\r
+               }\r
+               FreeBuf(b);\r
+       }\r
+\r
+       if (IsZero(a->ShortcutKey, SHA1_SIZE))\r
+       {\r
+               Rand(a->ShortcutKey, SHA1_SIZE);\r
+       }\r
+\r
+       return a;\r
+}\r
+\r
+// アカウントデータベースの読み込み\r
+void CiLoadAccountDatabase(CLIENT *c, FOLDER *f)\r
+{\r
+       TOKEN_LIST *t;\r
+       UINT i;\r
+       // 引数チェック\r
+       if (c == NULL || f == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       t = CfgEnumFolderToTokenList(f);\r
+       if (t == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       for (i = 0;i < t->NumTokens;i++)\r
+       {\r
+               FOLDER *ff = CfgGetFolder(f, t->Token[i]);\r
+\r
+               if (ff != NULL)\r
+               {\r
+                       ACCOUNT *a = CiLoadClientAccount(ff);\r
+                       if (a != NULL)\r
+                       {\r
+                               Add(c->AccountList, a);\r
+                       }\r
+               }\r
+       }\r
+\r
+       Sort(c->AccountList);\r
+\r
+       FreeToken(t);\r
+}\r
+\r
+// ルート CA 証明書を読み込む\r
+void CiLoadCACert(CLIENT *c, FOLDER *f)\r
+{\r
+       BUF *b;\r
+       X *x;\r
+       // 引数チェック\r
+       if (c == NULL || f == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       b = CfgGetBuf(f, "X509");\r
+       if (b == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       x = BufToX(b, false);\r
+\r
+       AddCa(c->Cedar, x);\r
+\r
+       FreeX(x);\r
+\r
+       FreeBuf(b);\r
+}\r
+\r
+// ルート CA リストを読み込む\r
+void CiLoadCAList(CLIENT *c, FOLDER *f)\r
+{\r
+       CEDAR *cedar;\r
+       TOKEN_LIST *t;\r
+       // 引数チェック\r
+       if (c == NULL || f == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       t = CfgEnumFolderToTokenList(f);\r
+\r
+       cedar = c->Cedar;\r
+\r
+       LockList(cedar->CaList);\r
+       {\r
+               UINT i;\r
+               for (i = 0;i < t->NumTokens;i++)\r
+               {\r
+                       FOLDER *folder = CfgGetFolder(f, t->Token[i]);\r
+                       CiLoadCACert(c, folder);\r
+               }\r
+       }\r
+       UnlockList(cedar->CaList);\r
+\r
+       FreeToken(t);\r
+}\r
+\r
+// VLAN を読み込む\r
+void CiLoadVLan(CLIENT *c, FOLDER *f)\r
+{\r
+       char tmp[MAX_SIZE];\r
+       UCHAR addr[6];\r
+       BUF *b;\r
+       UNIX_VLAN *v;\r
+       // 引数チェック\r
+       if (c == NULL || f == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       if (CfgGetStr(f, "MacAddress", tmp, sizeof(tmp)) == false)\r
+       {\r
+               return;\r
+       }\r
+\r
+       b = StrToBin(tmp);\r
+       if (b == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       if (b->Size != 6)\r
+       {\r
+               FreeBuf(b);\r
+               return;\r
+       }\r
+\r
+       Copy(addr, b->Buf, 6);\r
+\r
+       FreeBuf(b);\r
+\r
+       if (IsZero(addr, 6))\r
+       {\r
+               return;\r
+       }\r
+\r
+       v = ZeroMalloc(sizeof(UNIX_VLAN));\r
+       Copy(v->MacAddress, addr, 6);\r
+       StrCpy(v->Name, sizeof(v->Name), f->Name);\r
+       v->Enabled = CfgGetBool(f, "Enabled");\r
+\r
+       Add(c->UnixVLanList, v);\r
+\r
+#ifdef OS_UNIX\r
+       UnixVLanCreate(v->Name, v->MacAddress);\r
+#endif // OS_UNIX\r
+}\r
+\r
+// VLAN リストを読み込む\r
+void CiLoadVLanList(CLIENT *c, FOLDER *f)\r
+{\r
+       TOKEN_LIST *t;\r
+       // 引数チェック\r
+       if (c == NULL || f == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       t = CfgEnumFolderToTokenList(f);\r
+\r
+       LockList(c->UnixVLanList);\r
+       {\r
+               UINT i;\r
+               for (i = 0;i < t->NumTokens;i++)\r
+               {\r
+                       FOLDER *folder = CfgGetFolder(f, t->Token[i]);\r
+                       CiLoadVLan(c, folder);\r
+               }\r
+       }\r
+       UnlockList(c->UnixVLanList);\r
+\r
+       FreeToken(t);\r
+}\r
+\r
+// 設定ファイルから設定の読み込み\r
+bool CiReadSettingFromCfg(CLIENT *c, FOLDER *root)\r
+{\r
+       FOLDER *config;\r
+       FOLDER *cert;\r
+       FOLDER *db;\r
+       FOLDER *vlan;\r
+       FOLDER *cmsetting;\r
+       char user_agent[MAX_SIZE];\r
+       // 引数チェック\r
+       if (c == NULL || root == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       // Config と AccountDatabase の両方が無い場合は設定を初期化する\r
+       config = CfgGetFolder(root, "Config");\r
+       if (config == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       db = CfgGetFolder(root, "AccountDatabase");\r
+       if (db == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       cmsetting = CfgGetFolder(root, "ClientManagerSetting");\r
+\r
+       CiLoadClientConfig(&c->Config, config);\r
+\r
+       // 自動ファイル削除器\r
+       c->Eraser = NewEraser(c->Logger, CfgGetInt64(config, "AutoDeleteCheckDiskFreeSpaceMin"));\r
+\r
+       if (OS_IS_UNIX(GetOsInfo()->OsType) && GetOsInfo()->OsType != OSTYPE_MACOS_X)\r
+       {\r
+               // Unix 版仮想 LAN カード一覧の読み込み (MacOS の場合はしない)\r
+               vlan = CfgGetFolder(root, "UnixVLan");\r
+               if (vlan != NULL)\r
+               {\r
+                       CiLoadVLanList(c, vlan);\r
+               }\r
+       }\r
+\r
+       if (GetOsInfo()->OsType == OSTYPE_MACOS_X)\r
+       {\r
+#ifdef OS_UNIX\r
+               UNIX_VLAN *uv;\r
+\r
+               // MacOS X の場合は Tap を作成する\r
+               if (UnixVLanCreate(CLIENT_MACOS_TAP_NAME, NULL) == false)\r
+               {\r
+                       // 失敗 (強制終了)\r
+                       CLog(c, "LC_TAP_NOT_FOUND");\r
+                       Alert("tun/tap driver not found.", NULL);\r
+                       exit(0);\r
+               }\r
+\r
+               uv = ZeroMalloc(sizeof(UNIX_VLAN));\r
+               uv->Enabled = true;\r
+               StrCpy(uv->Name, sizeof(uv->Name), CLIENT_MACOS_TAP_NAME);\r
+               Add(c->UnixVLanList, uv);\r
+#endif // OS_UNIX\r
+       }\r
+\r
+       CiLoadAccountDatabase(c, db);\r
+\r
+       if (CfgGetByte(root, "EncryptedPassword", c->EncryptedPassword, SHA1_SIZE) == false)\r
+       {\r
+               Hash(c->EncryptedPassword, "", 0, true);\r
+       }\r
+\r
+       c->PasswordRemoteOnly = CfgGetBool(root, "PasswordRemoteOnly");\r
+       c->UseSecureDeviceId = CfgGetInt(root, "UseSecureDeviceId");\r
+\r
+       if (CfgGetStr(root, "UserAgent", user_agent, sizeof(user_agent)))\r
+       {\r
+               if (IsEmptyStr(user_agent) == false)\r
+               {\r
+                       Free(c->Cedar->HttpUserAgent);\r
+                       c->Cedar->HttpUserAgent = CopyStr(user_agent);\r
+               }\r
+       }\r
+\r
+       cert = CfgGetFolder(root, "RootCA");\r
+       if (cert != NULL)\r
+       {\r
+               CiLoadCAList(c, cert);\r
+       }\r
+\r
+       c->DontSavePassword = CfgGetBool(root, "DontSavePassword");\r
+\r
+       if (cmsetting != NULL)\r
+       {\r
+               UINT ostype = GetOsInfo()->OsType;\r
+               // CM_SETTING\r
+               CM_SETTING *s = c->CmSetting;\r
+\r
+               if (OS_IS_UNIX(ostype) || OS_IS_WINDOWS_NT(ostype))\r
+               {\r
+                       s->EasyMode = CfgGetBool(cmsetting, "EasyMode");\r
+               }\r
+\r
+               s->LockMode = CfgGetBool(cmsetting, "LockMode");\r
+               CfgGetByte(cmsetting, "HashedPassword", s->HashedPassword, sizeof(s->HashedPassword));\r
+       }\r
+\r
+       return true;\r
+}\r
+\r
+// 設定ファイルの読み込み\r
+bool CiLoadConfigurationFile(CLIENT *c)\r
+{\r
+       bool ret;\r
+       FOLDER *root;\r
+       // 引数チェック\r
+       if (c == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       // 設定ファイルの読み込み\r
+       c->CfgRw = NewCfgRw(&root, CLIENT_CONFIG_FILE_NAME);\r
+\r
+       if (root == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       ret = CiReadSettingFromCfg(c, root);\r
+\r
+       CfgDeleteFolder(root);\r
+\r
+       return ret;\r
+}\r
+\r
+// CLIENT_CONFIG を書き込む\r
+void CiWriteClientConfig(FOLDER *cc, CLIENT_CONFIG *config)\r
+{\r
+       // 引数チェック\r
+       if (cc == NULL || config == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       CfgAddBool(cc, "UseKeepConnect", config->UseKeepConnect);\r
+       CfgAddStr(cc, "KeepConnectHost", config->KeepConnectHost);\r
+       CfgAddInt(cc, "KeepConnectPort", config->KeepConnectPort);\r
+       CfgAddInt(cc, "KeepConnectProtocol", config->KeepConnectProtocol);\r
+       CfgAddBool(cc, "AllowRemoteConfig", config->AllowRemoteConfig);\r
+       CfgAddInt(cc, "KeepConnectInterval", config->KeepConnectInterval);\r
+}\r
+\r
+// クライアント認証データを書き込む\r
+void CiWriteClientAuth(FOLDER *f, CLIENT_AUTH *a)\r
+{\r
+       BUF *b;\r
+       // 引数チェック\r
+       if (f == NULL || a == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       CfgAddInt(f, "AuthType", a->AuthType);\r
+       CfgAddStr(f, "Username", a->Username);\r
+\r
+       switch (a->AuthType)\r
+       {\r
+       case CLIENT_AUTHTYPE_ANONYMOUS:\r
+               break;\r
+\r
+       case CLIENT_AUTHTYPE_PASSWORD:\r
+               CfgAddByte(f, "HashedPassword", a->HashedPassword, SHA1_SIZE);\r
+               break;\r
+\r
+       case CLIENT_AUTHTYPE_PLAIN_PASSWORD:\r
+               b = EncryptPassword(a->PlainPassword);\r
+               CfgAddByte(f, "EncryptedPassword", b->Buf, b->Size);\r
+               FreeBuf(b);\r
+               break;\r
+\r
+       case CLIENT_AUTHTYPE_CERT:\r
+               if (a->ClientK != NULL && a->ClientX != NULL)\r
+               {\r
+                       b = XToBuf(a->ClientX, false);\r
+                       CfgAddByte(f, "ClientCert", b->Buf, b->Size);\r
+                       FreeBuf(b);\r
+\r
+                       b = KToBuf(a->ClientK, false, NULL);\r
+                       CfgAddByte(f, "ClientKey", b->Buf, b->Size);\r
+                       FreeBuf(b);\r
+               }\r
+               break;\r
+\r
+       case CLIENT_AUTHTYPE_SECURE:\r
+               CfgAddStr(f, "SecurePublicCertName", a->SecurePublicCertName);\r
+               CfgAddStr(f, "SecurePrivateKeyName", a->SecurePrivateKeyName);\r
+               break;\r
+       }\r
+}\r
+\r
+// クライアントオプションを書き込む\r
+void CiWriteClientOption(FOLDER *f, CLIENT_OPTION *o)\r
+{\r
+       BUF *b;\r
+       // 引数チェック\r
+       if (f == NULL || o == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       CfgAddUniStr(f, "AccountName", o->AccountName);\r
+       CfgAddStr(f, "Hostname", o->Hostname);\r
+       CfgAddInt(f, "Port", o->Port);\r
+       CfgAddInt(f, "PortUDP", o->PortUDP);\r
+       CfgAddInt(f, "ProxyType", o->ProxyType);\r
+       CfgAddStr(f, "ProxyName", o->ProxyName);\r
+       CfgAddInt(f, "ProxyPort", o->ProxyPort);\r
+       CfgAddStr(f, "ProxyUsername", o->ProxyUsername);\r
+       b = EncryptPassword(o->ProxyPassword);\r
+       CfgAddByte(f, "ProxyPassword", b->Buf, b->Size);\r
+       FreeBuf(b);\r
+       CfgAddInt(f, "NumRetry", o->NumRetry);\r
+       CfgAddInt(f, "RetryInterval", o->RetryInterval);\r
+       CfgAddStr(f, "HubName", o->HubName);\r
+       CfgAddInt(f, "MaxConnection", o->MaxConnection);\r
+       CfgAddBool(f, "UseEncrypt", o->UseEncrypt);\r
+       CfgAddBool(f, "UseCompress", o->UseCompress);\r
+       CfgAddBool(f, "HalfConnection", o->HalfConnection);\r
+       CfgAddBool(f, "NoRoutingTracking", o->NoRoutingTracking);\r
+       CfgAddStr(f, "DeviceName", o->DeviceName);\r
+       CfgAddInt(f, "AdditionalConnectionInterval", o->AdditionalConnectionInterval);\r
+       CfgAddBool(f, "HideStatusWindow", o->HideStatusWindow);\r
+       CfgAddBool(f, "HideNicInfoWindow", o->HideNicInfoWindow);\r
+       CfgAddInt(f, "ConnectionDisconnectSpan", o->ConnectionDisconnectSpan);\r
+       CfgAddBool(f, "RequireMonitorMode", o->RequireMonitorMode);\r
+       CfgAddBool(f, "RequireBridgeRoutingMode", o->RequireBridgeRoutingMode);\r
+       CfgAddBool(f, "DisableQoS", o->DisableQoS);\r
+       CfgAddBool(f, "NoTls1", o->NoTls1);\r
+\r
+       if (o->FromAdminPack)\r
+       {\r
+               CfgAddBool(f, "FromAdminPack", o->FromAdminPack);\r
+       }\r
+}\r
+\r
+// パスワードの解読\r
+char *DecryptPassword(BUF *b)\r
+{\r
+       char *str;\r
+       char *key = "EncryptPassword";\r
+       CRYPT *c;\r
+       // 引数チェック\r
+       if (b == NULL)\r
+       {\r
+               return CopyStr("");\r
+       }\r
+\r
+       str = ZeroMalloc(b->Size + 1);\r
+       c = NewCrypt(key, sizeof(key));\r
+       Encrypt(c, str, b->Buf, b->Size);\r
+       FreeCrypt(c);\r
+\r
+       str[b->Size] = 0;\r
+\r
+       return str;\r
+}\r
+\r
+// パスワードの暗号化\r
+BUF *EncryptPassword(char *password)\r
+{\r
+       UCHAR *tmp;\r
+       UINT size;\r
+       char *key = "EncryptPassword";\r
+       CRYPT *c;\r
+       BUF *b;\r
+       // 引数チェック\r
+       if (password == NULL)\r
+       {\r
+               password = "";\r
+       }\r
+\r
+       size = StrLen(password) + 1;\r
+       tmp = ZeroMalloc(size);\r
+\r
+       c = NewCrypt(key, sizeof(key));\r
+       Encrypt(c, tmp, password, size - 1);\r
+       FreeCrypt(c);\r
+\r
+       b = NewBuf();\r
+       WriteBuf(b, tmp, size - 1);\r
+       SeekBuf(b, 0, 0);\r
+       Free(tmp);\r
+\r
+       return b;\r
+}\r
+\r
+// アカウントデータを書き込む\r
+void CiWriteAccountData(FOLDER *f, ACCOUNT *a)\r
+{\r
+       // 引数チェック\r
+       if (f == NULL || a == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       // クライアントオプション\r
+       CiWriteClientOption(CfgCreateFolder(f, "ClientOption"), a->ClientOption);\r
+\r
+       // クライアント認証データ\r
+       CiWriteClientAuth(CfgCreateFolder(f, "ClientAuth"), a->ClientAuth);\r
+\r
+       // スタートアップアカウント\r
+       CfgAddBool(f, "StartupAccount", a->StartupAccount);\r
+\r
+       // サーバー証明書チェックフラグ\r
+       CfgAddBool(f, "CheckServerCert", a->CheckServerCert);\r
+\r
+       // 日時\r
+       CfgAddInt64(f, "CreateDateTime", a->CreateDateTime);\r
+       CfgAddInt64(f, "UpdateDateTime", a->UpdateDateTime);\r
+       CfgAddInt64(f, "LastConnectDateTime", a->LastConnectDateTime);\r
+\r
+       // サーバー証明書本体\r
+       if (a->ServerCert != NULL)\r
+       {\r
+               BUF *b = XToBuf(a->ServerCert, false);\r
+               if (b != NULL)\r
+               {\r
+                       CfgAddBuf(f, "ServerCert", b);\r
+                       FreeBuf(b);\r
+               }\r
+       }\r
+\r
+       // ショートカットキー\r
+       if (IsZero(a->ShortcutKey, SHA1_SIZE) == false)\r
+       {\r
+               char tmp[64];\r
+               BinToStr(tmp, sizeof(tmp), a->ShortcutKey, SHA1_SIZE);\r
+               CfgAddStr(f, "ShortcutKey", tmp);\r
+       }\r
+}\r
+\r
+// アカウントデータベースを書き込む\r
+void CiWriteAccountDatabase(CLIENT *c, FOLDER *f)\r
+{\r
+       char name[MAX_SIZE];\r
+       // 引数チェック\r
+       if (c == NULL || f == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       LockList(c->AccountList);\r
+       {\r
+               UINT i;\r
+               for (i = 0;i < LIST_NUM(c->AccountList);i++)\r
+               {\r
+                       ACCOUNT *a = LIST_DATA(c->AccountList, i);\r
+                       Format(name, sizeof(name), "Account%u", i);\r
+                       Lock(a->lock);\r
+                       {\r
+                               CiWriteAccountData(CfgCreateFolder(f, name), a);\r
+                       }\r
+                       Unlock(a->lock);\r
+               }\r
+       }\r
+       UnlockList(c->AccountList);\r
+}\r
+\r
+// CA 証明書を書き込む\r
+void CiWriteCACert(CLIENT *c, FOLDER *f, X *x)\r
+{\r
+       BUF *b;\r
+       // 引数チェック\r
+       if (c == NULL || f == NULL || x == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       b = XToBuf(x, false);\r
+       CfgAddBuf(f, "X509", b);\r
+       FreeBuf(b);\r
+}\r
+\r
+// VLAN を書き込む\r
+void CiWriteVLan(CLIENT *c, FOLDER *f, UNIX_VLAN *v)\r
+{\r
+       char tmp[MAX_SIZE];\r
+       // 引数チェック\r
+       if (c == NULL || f == NULL || v == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       MacToStr(tmp, sizeof(tmp), v->MacAddress);\r
+       CfgAddStr(f, "MacAddress", tmp);\r
+       CfgAddBool(f, "Enabled", v->Enabled);\r
+}\r
+\r
+// VLAN リストを書き込む\r
+void CiWriteVLanList(CLIENT *c, FOLDER *f)\r
+{\r
+       // 引数チェック\r
+       if (c == NULL || f == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       LockList(c->UnixVLanList);\r
+       {\r
+               UINT i;\r
+               for (i = 0;i < LIST_NUM(c->UnixVLanList);i++)\r
+               {\r
+                       UNIX_VLAN *v = LIST_DATA(c->UnixVLanList, i);\r
+                       CiWriteVLan(c, CfgCreateFolder(f, v->Name), v);\r
+               }\r
+       }\r
+       UnlockList(c->UnixVLanList);\r
+}\r
+\r
+// CA リストを書き込む\r
+void CiWriteCAList(CLIENT *c, FOLDER *f)\r
+{\r
+       CEDAR *cedar;\r
+       // 引数チェック\r
+       if (c == NULL || f == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       cedar = c->Cedar;\r
+\r
+       LockList(cedar->CaList);\r
+       {\r
+               UINT i;\r
+               for (i = 0;i < LIST_NUM(cedar->CaList);i++)\r
+               {\r
+                       char tmp[MAX_SIZE];\r
+                       X *x = LIST_DATA(cedar->CaList, i);\r
+                       Format(tmp, sizeof(tmp), "Certificate%u", i);\r
+                       CiWriteCACert(c, CfgCreateFolder(f, tmp), x);\r
+               }\r
+       }\r
+       UnlockList(cedar->CaList);\r
+}\r
+\r
+// 現在の設定を ROOT に書き込む\r
+void CiWriteSettingToCfg(CLIENT *c, FOLDER *root)\r
+{\r
+       FOLDER *cc;\r
+       FOLDER *account_database;\r
+       FOLDER *ca;\r
+       FOLDER *vlan;\r
+       FOLDER *cmsetting;\r
+       // 引数チェック\r
+       if (c == NULL || root == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       cmsetting = CfgCreateFolder(root, "ClientManagerSetting");\r
+\r
+       // CLIENT_CONFIG\r
+       cc = CfgCreateFolder(root, "Config");\r
+       CiWriteClientConfig(cc, &c->Config);\r
+\r
+       // 自動ファイル削除器\r
+       CfgAddInt64(cc, "AutoDeleteCheckDiskFreeSpaceMin", c->Eraser->MinFreeSpace);\r
+\r
+       // Account Database\r
+       account_database = CfgCreateFolder(root, "AccountDatabase");\r
+       CiWriteAccountDatabase(c, account_database);\r
+\r
+       // CA\r
+       ca = CfgCreateFolder(root, "RootCA");\r
+       CiWriteCAList(c, ca);\r
+\r
+       // VLAN\r
+       if (OS_IS_UNIX(GetOsInfo()->OsType) && GetOsInfo()->OsType != OSTYPE_MACOS_X)\r
+       {\r
+               vlan = CfgCreateFolder(root, "UnixVLan");\r
+               CiWriteVLanList(c, vlan);\r
+       }\r
+\r
+       // Password\r
+       CfgAddByte(root, "EncryptedPassword", c->EncryptedPassword, SHA1_SIZE);\r
+       CfgAddBool(root, "PasswordRemoteOnly", c->PasswordRemoteOnly);\r
+\r
+       // UseSecureDeviceId\r
+       CfgAddInt(root, "UseSecureDeviceId", c->UseSecureDeviceId);\r
+\r
+       // DontSavePassword\r
+       CfgAddBool(root, "DontSavePassword", c->DontSavePassword);\r
+\r
+       // UserAgent\r
+       if (c->Cedar != NULL)\r
+       {\r
+               CfgAddStr(root, "UserAgent", c->Cedar->HttpUserAgent);\r
+       }\r
+\r
+       if (cmsetting != NULL)\r
+       {\r
+               CM_SETTING *s = c->CmSetting;\r
+\r
+               CfgAddBool(cmsetting, "EasyMode", s->EasyMode);\r
+               CfgAddBool(cmsetting, "LockMode", s->LockMode);\r
+\r
+               if (IsZero(s->HashedPassword, sizeof(s->HashedPassword)) == false)\r
+               {\r
+                       CfgAddByte(cmsetting, "HashedPassword", s->HashedPassword, sizeof(s->HashedPassword));\r
+               }\r
+       }\r
+}\r
+\r
+// 設定ファイルへ書き込み\r
+void CiSaveConfigurationFile(CLIENT *c)\r
+{\r
+       FOLDER *root;\r
+       // 引数チェック\r
+       if (c == NULL)\r
+       {\r
+               return;\r
+       }\r
+       \r
+       // 設定ファイルを保存しない\r
+       if(c->NoSaveConfig)\r
+       {\r
+               return;\r
+       }\r
+\r
+       root = CfgCreateFolder(NULL, TAG_ROOT);\r
+       CiWriteSettingToCfg(c, root);\r
+\r
+       SaveCfgRw(c->CfgRw, root);\r
+\r
+       CfgDeleteFolder(root);\r
+}\r
+\r
+// CM_SETTING の設定\r
+bool CtSetCmSetting(CLIENT *c, CM_SETTING *s)\r
+{\r
+       // 引数チェック\r
+       if (c == NULL || s == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       Copy(c->CmSetting, s, sizeof(CM_SETTING));\r
+\r
+       CiSaveConfigurationFile(c);\r
+\r
+       return true;\r
+}\r
+\r
+// CM_SETTING の取得\r
+bool CtGetCmSetting(CLIENT *c, CM_SETTING *s)\r
+{\r
+       // 引数チェック\r
+       if (c == NULL || s == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       Copy(s, c->CmSetting, sizeof(CM_SETTING));\r
+       \r
+       return true;\r
+}\r
+\r
+// クライアントバージョンの取得\r
+bool CtGetClientVersion(CLIENT *c, RPC_CLIENT_VERSION *ver)\r
+{\r
+       // 引数チェック\r
+       if (ver == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       Zero(ver, sizeof(RPC_CLIENT_VERSION));\r
+       StrCpy(ver->ClientProductName, sizeof(ver->ClientProductName), CEDAR_CLIENT_STR);\r
+       StrCpy(ver->ClientVersionString, sizeof(ver->ClientVersionString), c->Cedar->VerString);\r
+       StrCpy(ver->ClientBuildInfoString, sizeof(ver->ClientBuildInfoString), c->Cedar->BuildInfo);\r
+       ver->ClientVerInt = c->Cedar->Version;\r
+       ver->ClientBuildInt = c->Cedar->Build;\r
+\r
+#ifdef OS_WIN32\r
+       ver->ProcessId = MsGetProcessId();\r
+#endif // OS_WIN32\r
+\r
+       ver->OsType = GetOsInfo()->OsType;\r
+\r
+       return true;\r
+}\r
+\r
+// クライアントオブジェクトの作成\r
+CLIENT *CiNewClient()\r
+{\r
+       CLIENT *c = ZeroMalloc(sizeof(CLIENT));\r
+\r
+//     StartCedarLog();\r
+\r
+       c->CmSetting = ZeroMalloc(sizeof(CM_SETTING));\r
+\r
+       c->SockList = NewSockList();\r
+\r
+       c->lock = NewLock();\r
+       c->lockForConnect = NewLock();\r
+       c->ref = NewRef();\r
+\r
+       c->Cedar = NewCedar(NULL, NULL);\r
+\r
+       c->Cedar->Client = c;\r
+\r
+       c->NotifyCancelList = NewList(NULL);\r
+\r
+       Hash(c->EncryptedPassword, "", 0, true);\r
+\r
+       // ログ設定\r
+       if(c->NoSaveLog == false)\r
+       {\r
+               MakeDir(CLIENT_LOG_DIR_NAME);\r
+               c->Logger = NewLog(CLIENT_LOG_DIR_NAME, CLIENT_LOG_PREFIX, LOG_SWITCH_DAY);\r
+       }\r
+\r
+       CLog(c, "L_LINE");\r
+       CLog(c, "LC_START_2", CEDAR_CLIENT_STR, c->Cedar->VerString);\r
+       CLog(c, "LC_START_3", c->Cedar->BuildInfo);\r
+       CLog(c, "LC_START_1");\r
+\r
+#ifdef OS_WIN32\r
+       {\r
+               // Win32 UI の初期化\r
+               wchar_t tmp[MAX_SIZE];\r
+               StrToUni(tmp, sizeof(tmp), CEDAR_CLIENT_STR);\r
+\r
+               InitWinUi(tmp, _SS("DEFAULT_FONT"), _II("DEFAULT_FONT_SIZE"));\r
+       }\r
+#endif // OS_WIN32\r
+\r
+       // 設定の初期化\r
+       CiInitConfiguration(c);\r
+\r
+       // 優先順位を上げる\r
+       OSSetHighPriority();\r
+\r
+#ifdef OS_WIN32\r
+       // Win9x の場合、すべての仮想 LAN カードの DHCP アドレスを解放する\r
+       if (MsIsNt() == false)\r
+       {\r
+               Win32ReleaseAllDhcp9x(true);\r
+       }\r
+#endif // OS_WIN32\r
+\r
+       CiChangeAllVLanMacAddressIfMachineChanged(c);\r
+\r
+       return c;\r
+}\r
+\r
+// クライアントのクリーンアップ\r
+void CiCleanupClient(CLIENT *c)\r
+{\r
+       // 引数チェック\r
+       if (c == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       // 設定の解放\r
+       CiFreeConfiguration(c);\r
+\r
+#ifdef OS_WIN32\r
+       // Win32 UI の解放\r
+       FreeWinUi();\r
+#endif // OS_WIN32\r
+\r
+       CLog(c, "LC_END");\r
+       CLog(c, "L_LINE");\r
+       FreeEraser(c->Eraser);\r
+       FreeLog(c->Logger);\r
+       c->Logger = NULL;\r
+\r
+       ReleaseCedar(c->Cedar);\r
+\r
+       DeleteLock(c->lockForConnect);\r
+       DeleteLock(c->lock);\r
+\r
+       ReleaseList(c->NotifyCancelList);\r
+\r
+       FreeSockList(c->SockList);\r
+\r
+       Free(c->CmSetting);\r
+\r
+       Free(c);\r
+\r
+#ifdef OS_WIN32\r
+       // Win9x の場合、すべての仮想 LAN カードの DHCP アドレスを解放する\r
+       if (MsIsNt() == false)\r
+       {\r
+               Win32ReleaseAllDhcp9x(true);\r
+       }\r
+#endif // OS_WIN32\r
+\r
+       StopCedarLog();\r
+}\r
+\r
+// クライアントの解放\r
+void CtReleaseClient(CLIENT *c)\r
+{\r
+       // 引数チェック\r
+       if (c == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       if (Release(c->ref) == 0)\r
+       {\r
+               CiCleanupClient(c);\r
+       }\r
+}\r
+\r
+// クライアントプログラムの動作開始\r
+void CtStartClient()\r
+{\r
+       UINT i;\r
+       LIST *o;\r
+       if (client != NULL)\r
+       {\r
+               // すでに動作している\r
+               return;\r
+       }\r
+\r
+       // OS チェック\r
+       CiCheckOs();\r
+\r
+#ifdef OS_WIN32\r
+       RegistWindowsFirewallAll();\r
+#endif\r
+\r
+       // クライアントの作成\r
+       client = CiNewClient();\r
+\r
+       // Keep を開始\r
+       CiInitKeep(client);\r
+\r
+       // RPC サーバーを開始\r
+       CiStartRpcServer(client);\r
+\r
+       // 設定データ自動保存を開始\r
+       CiInitSaver(client);\r
+\r
+       // スタートアップ接続を開始する\r
+       o = NewListFast(NULL);\r
+       LockList(client->AccountList);\r
+       {\r
+               for (i = 0;i < LIST_NUM(client->AccountList);i++)\r
+               {\r
+                       ACCOUNT *a = LIST_DATA(client->AccountList, i);\r
+                       Lock(a->lock);\r
+                       {\r
+                               if (a->StartupAccount)\r
+                               {\r
+                                       Add(o, CopyUniStr(a->ClientOption->AccountName));\r
+                               }\r
+                       }\r
+                       Unlock(a->lock);\r
+               }\r
+       }\r
+       UnlockList(client->AccountList);\r
+\r
+       for (i = 0;i < LIST_NUM(o);i++)\r
+       {\r
+               wchar_t *s = LIST_DATA(o, i);\r
+               RPC_CLIENT_CONNECT c;\r
+               Zero(&c, sizeof(c));\r
+               UniStrCpy(c.AccountName, sizeof(c.AccountName), s);\r
+               CtConnect(client, &c);\r
+               Free(s);\r
+       }\r
+       ReleaseList(o);\r
+}\r
+\r
+// クライアントプログラムの動作終了\r
+void CtStopClient()\r
+{\r
+       UINT i, num;\r
+       ACCOUNT **account_list;\r
+       if (client == NULL)\r
+       {\r
+               // まだ動作していない\r
+               return;\r
+       }\r
+\r
+       // 停止フラグ\r
+       client->Halt = true;\r
+\r
+       // RPC をすべて切断\r
+       CiStopRpcServer(client);\r
+\r
+       // クライアント通知サービスを終了\r
+       CncExit();\r
+\r
+       // Keep を終了\r
+       CiFreeKeep(client);\r
+\r
+       // 接続中のアカウントをすべて切断\r
+       LockList(client->AccountList);\r
+       {\r
+               num = LIST_NUM(client->AccountList);\r
+               account_list = ToArray(client->AccountList);\r
+       }\r
+       UnlockList(client->AccountList);\r
+\r
+       for (i = 0;i < num;i++)\r
+       {\r
+               ACCOUNT *a = account_list[i];\r
+               SESSION *s = NULL;\r
+\r
+               Lock(a->lock);\r
+               {\r
+                       if (a->ClientSession != NULL)\r
+                       {\r
+                               s = a->ClientSession;\r
+                               AddRef(s->ref);\r
+                       }\r
+               }\r
+               Unlock(a->lock);\r
+\r
+               if (s != NULL)\r
+               {\r
+                       StopSession(s);\r
+                       ReleaseSession(s);\r
+                       Lock(a->lock);\r
+                       {\r
+                               if (a->ClientSession != NULL)\r
+                               {\r
+                                       ReleaseSession(a->ClientSession);\r
+                                       a->ClientSession = NULL;\r
+                               }\r
+                       }\r
+                       Unlock(a->lock);\r
+               }\r
+       }\r
+\r
+       Free(account_list);\r
+\r
+       // 設定データ自動保存を停止\r
+       CiFreeSaver(client);\r
+\r
+       // クライアントの解放\r
+       CtReleaseClient(client);\r
+       client = NULL;\r
+}\r
+\r
+// OS チェック\r
+void CiCheckOs()\r
+{\r
+       // OS の種類の取得\r
+       OS_INFO *info = GetOsInfo();\r
+\r
+       if (OS_IS_WINDOWS(info->OsType))\r
+       {\r
+               bool ok = IS_CLIENT_SUPPORTED_OS(info->OsType);\r
+\r
+               if (ok == false)\r
+               {\r
+                       Alert(\r
+                               "SoftEther UT-VPN Client doesn't support this Windows Operating System.\n"\r
+                               "SoftEther UT-VPN Client requires Windows 98 SE, Windows Me, Windows 2000, Windows XP, Windows Server 2003 or Greater.\n\n"\r
+                               "Please contact your system administrator.", "SoftEther UT-VPN Client");\r
+                       exit(0);\r
+               }\r
+       }\r
+}\r
+\r
+// クライアントオブジェクトの取得\r
+CLIENT *CtGetClient()\r
+{\r
+       if (client == NULL)\r
+       {\r
+               return NULL;\r
+       }\r
+\r
+       AddRef(client->ref);\r
+\r
+       return client;\r
+}\r
+\r
+// クライアントステータス表示器\r
+void CiClientStatusPrinter(SESSION *s, wchar_t *status)\r
+{\r
+#ifdef OS_WIN32\r
+       ACCOUNT *a;\r
+       // 引数チェック\r
+       if (s == NULL || status == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       a = s->Account;\r
+       if (a == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       if (UniStrCmpi(status, L"init") == 0)\r
+       {\r
+               if (a->StatusWindow == NULL && s->Win32HideConnectWindow == false)\r
+               {\r
+                       a->StatusWindow = CncStatusPrinterWindowStart(s);\r
+               }\r
+       }\r
+       else if (UniStrCmpi(status, L"free") == 0)\r
+       {\r
+               if (a->StatusWindow != NULL)\r
+               {\r
+                       CncStatusPrinterWindowStop(a->StatusWindow);\r
+                       a->StatusWindow = NULL;\r
+               }\r
+       }\r
+       else\r
+       {\r
+               if (a->StatusWindow != NULL)\r
+               {\r
+                       CncStatusPrinterWindowPrint(a->StatusWindow, status);\r
+               }\r
+       }\r
+#else  // OS_WIN32\r
+       UniPrint(L"Status: %s\n", status);\r
+#endif // OS_WIN32\r
+}\r
+\r
+\r