├── .gitattributes ├── .gitignore ├── Cargo.toml ├── README.md ├── build.rs ├── libs ├── CQP.def └── CQP.dll └── src ├── cqpapi ├── base_struct │ ├── group.rs │ ├── member.rs │ ├── mod.rs │ └── utils.rs └── mod.rs └── lib.rs /.gitattributes: -------------------------------------------------------------------------------- 1 | libs/CQP.dll filter=lfs diff=lfs merge=lfs -text 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cqpsdk" 3 | version = "0.0.1" 4 | authors = [ "evshiron", "doylecnn" ] 5 | 6 | [dependencies] 7 | encoding = "0.2" 8 | byteorder="1" 9 | base64 = "~0.6.0" 10 | serde="1.0" 11 | serde_derive ="1.0" 12 | 13 | [lib] 14 | name = "cqpsdk" 15 | crate-type = [ "rlib" ] -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Unofficial CQP SDK for Rust 2 | 3 | This project is a SDK for [CQP](https://cqp.cc/) written in [Rust](http://rust-lang.org/). 4 | 5 | The officially recognized Rust SDK is done by `doylecnn` and is linked in the Relative Projects section below. 6 | 7 | ## How To Use 8 | 9 | Add following lines to your `Cargo.toml`: 10 | 11 | ``` 12 | 13 | [dependencies.cqpsdk] 14 | git = "https://github.com/evshiron/cqpsdk-rust" 15 | 16 | ``` 17 | 18 | For more detailed information you can refer to [evshiron/PupuriumR](https://github.com/evshiron/PupuriumR/) as a demo. 19 | 20 | ## Documentation 21 | 22 | You can generate some documentation locally with the following commands: 23 | 24 | ```bash 25 | 26 | rustdoc ./src/mod.rs 27 | 28 | # Open the generated pages in Mac OS X. 29 | open ./doc/mod/index.html 30 | 31 | ``` 32 | 33 | Besides, the [evshiron/PupuriumR Wiki](https://github.com/evshiron/PupuriumR/wiki) might worth reading. 34 | 35 | ## Relative Projects 36 | 37 | * [doylecnn/cqpsdk-rust](https://github.com/evshiron/PupuriumR/) 38 | * [doylecnn/cqpsdk-rust-demo](https://github.com/doylecnn/cqpsdk-rust-demo) 39 | 40 | ## Thanks 41 | 42 | Many thanks to `doylecnn` and `Coxxs`, without whom I can't make this "another" SDK happen. 43 | 44 | ## Disclaimer 45 | 46 | I participated with the official Rust SDK with `doylecnn`, but we seperated because he wanted to make the code more of Rust style, while I love the raw C style API. 47 | 48 | ## The MIT License 49 | 50 | Copyright © 2015 evshiron 51 | 52 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 53 | 54 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 55 | 56 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 57 | -------------------------------------------------------------------------------- /build.rs: -------------------------------------------------------------------------------- 1 | pub fn main() 2 | { 3 | println!("cargo:rustc-link-search=./libs"); 4 | } -------------------------------------------------------------------------------- /libs/CQP.def: -------------------------------------------------------------------------------- 1 | LIBRARY CQP.dll 2 | EXPORTS 3 | CQ_addLog@16 4 | CQ_canSendImage 5 | CQ_canSendRecord 6 | CQ_deleteMsg@12 7 | CQ_getAppDirectory@4 8 | CQ_getCookies@4 9 | CQ_getCookiesV2 10 | CQ_getCsrfToken@4 11 | CQ_getFriendList 12 | CQ_getGroupInfo 13 | CQ_getGroupList@4 14 | CQ_getGroupMemberInfo 15 | CQ_getGroupMemberInfoV2@24 16 | CQ_getGroupMemberList@12 17 | CQ_getImage 18 | CQ_getLoginNick@4 19 | CQ_getLoginQQ@4 20 | CQ_getRecord@12 21 | CQ_getRecordV2 22 | CQ_getStrangerInfo@16 23 | CQ_sendDiscussMsg@16 24 | CQ_sendGroupMsg@16 25 | CQ_sendLike 26 | CQ_sendLikeV2@16 27 | CQ_sendPrivateMsg@16 28 | CQ_setDiscussLeave@12 29 | CQ_setFatal@8 30 | CQ_setFriendAddRequest@16 31 | CQ_setFunctionMark@8 32 | CQ_setGroupAddRequest 33 | CQ_setGroupAddRequestV2@20 34 | CQ_setGroupAdmin@24 35 | CQ_setGroupAnonymous@16 36 | CQ_setGroupAnonymousBan@24 37 | CQ_setGroupBan@28 38 | CQ_setGroupCard@24 39 | CQ_setGroupKick@24 40 | CQ_setGroupLeave@16 41 | CQ_setGroupSpecialTitle@32 42 | CQ_setGroupWholeBan@16 43 | cq_start 44 | -------------------------------------------------------------------------------- /libs/CQP.dll: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:d4b0e835c32ba95c96d404e36fe3310be14856de9530d9124264be51cd246a6c 3 | size 408016 4 | -------------------------------------------------------------------------------- /src/cqpapi/base_struct/group.rs: -------------------------------------------------------------------------------- 1 | use base64; 2 | 3 | use super::utils; 4 | 5 | #[derive(Serialize, Deserialize, Debug)] 6 | pub struct Group{ 7 | id :i64, 8 | name :String 9 | } 10 | 11 | impl Group{ 12 | fn from_bytes(bytes: &[u8])->Group{ 13 | let (group_id,left_index) = utils::get_i64(&bytes, 0); 14 | let (group_name,_) = utils::get_string(&bytes, left_index); 15 | Group{id:group_id, name:group_name} 16 | } 17 | 18 | pub fn parse_to_group_list(rawdata: &str)->Vec{ 19 | let bytes = base64::decode(rawdata).unwrap(); 20 | 21 | let mut left_index :usize = 0; 22 | let mut right_index :usize = 4; 23 | let (count, _) = utils::get_usize(&bytes, left_index, 4); 24 | 25 | let mut group_list : Vec = Vec::with_capacity(count); 26 | 27 | for _ in 0..count{ 28 | left_index = right_index; 29 | let (token_size,left_index) = utils::get_usize(&bytes, left_index, 2); 30 | 31 | right_index = left_index + token_size; 32 | let token = &bytes[left_index..right_index]; 33 | 34 | let g = Group::from_bytes(&token); 35 | group_list.push(g); 36 | } 37 | group_list 38 | } 39 | } -------------------------------------------------------------------------------- /src/cqpapi/base_struct/member.rs: -------------------------------------------------------------------------------- 1 | use base64; 2 | 3 | use super::utils; 4 | 5 | #[derive(Serialize, Deserialize, Debug)] 6 | pub struct Member{ 7 | group_id :i64, 8 | qq_id :i64, 9 | nickname :String, 10 | namecard :String, 11 | sex :i32, 12 | age :i32, 13 | area :String, 14 | join_time :i32, 15 | last_active :i32, 16 | level_name :String, 17 | permission :i32, 18 | bad_record :bool, 19 | special_title :String, 20 | special_title_express_time :i32, 21 | allow_modify_namecard :bool 22 | } 23 | 24 | impl Member{ 25 | fn from_bytes(bytes: &[u8])->Member{ 26 | let (group_id, offset) = utils::get_i64(&bytes, 0); 27 | let (qq_id, offset) = utils::get_i64(&bytes, offset); 28 | let (nickname, offset) = utils::get_string(&bytes, offset); 29 | let (namecard, offset) = utils::get_string(&bytes, offset); 30 | let (sex, offset) = utils::get_i32(&bytes, offset); 31 | let (age, offset) = utils::get_i32(&bytes, offset); 32 | let (area, offset) = utils::get_string(&bytes, offset); 33 | let (join_time, offset) = utils::get_i32(&bytes, offset); 34 | let (last_active, offset) = utils::get_i32(&bytes, offset); 35 | let (level_name, offset) = utils::get_string(&bytes, offset); 36 | let (permission, offset) = utils::get_i32(&bytes, offset); 37 | let (bad_record, offset) = utils::get_i32(&bytes, offset); 38 | let bad_record = bad_record == 1; 39 | let (special_title, offset) = utils::get_string(&bytes, offset); 40 | let (special_title_express_time, offset) = utils::get_i32(&bytes, offset); 41 | let (allow_modify_namecard, _) = utils::get_i32(&bytes, offset); 42 | let allow_modify_namecard = allow_modify_namecard == 1; 43 | 44 | Member{group_id :group_id, 45 | qq_id :qq_id, 46 | nickname :nickname, 47 | namecard :namecard, 48 | sex :sex, 49 | age :age, 50 | area :area, 51 | join_time :join_time, 52 | last_active :last_active, 53 | level_name :level_name, 54 | permission :permission, 55 | bad_record :bad_record, 56 | special_title :special_title, 57 | special_title_express_time :special_title_express_time, 58 | allow_modify_namecard :allow_modify_namecard} 59 | } 60 | 61 | pub fn parse_to_member(rawdata: &str)->Member{ 62 | let bytes = base64::decode(rawdata).unwrap(); 63 | Member::from_bytes(&bytes) 64 | } 65 | 66 | pub fn parse_to_member_list(rawdata: &str)->Vec{ 67 | let bytes = base64::decode(rawdata).unwrap(); 68 | 69 | let mut left_index :usize = 0; 70 | let mut right_index :usize = 4; 71 | let (count, _) = utils::get_usize(&bytes, left_index, 4); 72 | 73 | let mut member_list : Vec = Vec::with_capacity(count); 74 | 75 | for _ in 0..count{ 76 | left_index = right_index; 77 | let (token_size,left_index) = utils::get_usize(&bytes, left_index, 2); 78 | 79 | right_index = left_index + token_size; 80 | let token = &bytes[left_index..right_index]; 81 | let m = Member::from_bytes(token); 82 | 83 | member_list.push(m); 84 | } 85 | member_list 86 | } 87 | } -------------------------------------------------------------------------------- /src/cqpapi/base_struct/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod group; 2 | pub mod member; 3 | mod utils; -------------------------------------------------------------------------------- /src/cqpapi/base_struct/utils.rs: -------------------------------------------------------------------------------- 1 | use byteorder; 2 | use byteorder::ByteOrder; 3 | use encoding::{Encoding, DecoderTrap}; 4 | use encoding::all::GB18030; 5 | 6 | pub fn get_i16(ref bytes :&[u8], index :usize)->(i16, usize){ 7 | let left_index = index; 8 | let right_index = left_index + 2; 9 | (byteorder::BigEndian::read_i16(&bytes[left_index..right_index]), right_index) 10 | } 11 | 12 | pub fn get_i32(ref bytes :&[u8], index :usize)->(i32, usize){ 13 | let left_index = index; 14 | let right_index = left_index + 4; 15 | (byteorder::BigEndian::read_i32(&bytes[left_index..right_index]), right_index) 16 | } 17 | 18 | pub fn get_i64(ref bytes :&[u8], index :usize)->(i64, usize){ 19 | let left_index = index; 20 | let right_index = left_index + 8; 21 | (byteorder::BigEndian::read_i64(&bytes[left_index..right_index]), right_index) 22 | } 23 | 24 | pub fn get_string(ref bytes :&[u8], index :usize)->(String, usize){ 25 | let (len, left_index) = get_usize(&bytes, index, 2); 26 | let right_index = left_index + len; 27 | (GB18030.decode(&bytes[left_index..right_index], DecoderTrap::Ignore).unwrap(), right_index) 28 | } 29 | 30 | pub fn get_usize(ref bytes :&[u8], index :usize, len :usize)->(usize, usize){ 31 | match len { 32 | 2=>{ 33 | let (size, index) = get_i16(&bytes, index); 34 | return (size as usize, index); 35 | } 36 | 4=>{ 37 | let (size, index) = get_i32(&bytes, index); 38 | return (size as usize, index); 39 | } 40 | _ =>{ 41 | return (0, 0) 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /src/cqpapi/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod base_struct; 2 | pub struct Group; 3 | pub struct Member; 4 | 5 | use std::os::raw::c_char; 6 | 7 | #[link(name = "CQP")] 8 | #[allow(non_snake_case)] 9 | #[allow(dead_code)] 10 | extern "stdcall" { 11 | 12 | /// Sends private message. 13 | /// Auth=161 14 | /// return message_id 15 | /// 16 | /// # Examples 17 | /// 18 | /// ``` 19 | /// cqpsdk::cqpapi::CQ_sendPrivateMsg(AuthCode, 10000, UTF8_STR_TO_GB18030_C_CHAR_PTR!("Hello world!")); 20 | /// ``` 21 | /// 22 | pub fn CQ_sendPrivateMsg(AuthCode: i32, qqNum: i64, msg: *const c_char) -> i32; 23 | 24 | /// Sends group message. 25 | /// Auth=101 26 | /// return message_id 27 | /// 28 | /// # Examples 29 | /// 30 | /// ``` 31 | /// // cqpsdk::cqpapi::CQ_sendGroupMsg(AuthCode, 10000, UTF8_STR_TO_GB18030_C_CHAR_PTR!("Hello world!")); 32 | /// ``` 33 | /// 34 | pub fn CQ_sendGroupMsg(AuthCode: i32, groupNum: i64, msg: *const c_char) -> i32; 35 | 36 | /// Sends discussion message. 37 | /// Auth=103 38 | /// return message_id 39 | /// 40 | /// # Examples 41 | /// 42 | /// ``` 43 | /// // cqpsdk::cqpapi::CQ_sendDiscussMsg(AuthCode, 10000, UTF8_STR_TO_GB18030_C_CHAR_PTR!("Hello world!")); 44 | /// ``` 45 | /// 46 | pub fn CQ_sendDiscussMsg(AuthCode: i32, discussionNum: i64, msg: *const c_char) -> i32; 47 | 48 | /// Delete message 49 | /// Auth=180 50 | pub fn CQ_deleteMsg(AuthCode: i32, MsgId: i64) -> i32; 51 | 52 | /// Send good to user 53 | /// times max is 10 54 | /// Auth=110 55 | pub fn CQ_sendLikeV2(AuthCode: i32, qqNum: i64, times: i32) -> i32; 56 | 57 | /// Haven't been documented. 58 | /// Auth=120 59 | pub fn CQ_setGroupKick(AuthCode: i32, groupNum: i64, qqNum: i64, refuseRejoin: i32) -> i32; 60 | 61 | /// Haven't been documented. 62 | /// Auth=121 63 | pub fn CQ_setGroupBan(AuthCode: i32, groupNum: i64, qqNum: i64, banTime: i64) -> i32; 64 | 65 | /// Haven't been documented. 66 | /// Auth=122 67 | pub fn CQ_setGroupAdmin(AuthCode: i32, groupNum: i64, qqNum: i64, becomeAdmin: i32) -> i32; 68 | 69 | /// Set group special title 70 | /// Auth=128 71 | /// specialTitle, set empty means delete 72 | /// expireTime is seconds, if -1 means forever 73 | pub fn CQ_setGroupSpecialTitle(AuthCode: i32, groupNum: i64, qqNum: i64, specialTitle: *const c_char, expireTime:i64) -> i32; 74 | 75 | /// Haven't been documented. 76 | /// Auth=123 77 | pub fn CQ_setGroupWholeBan(AuthCode: i32, groupNum: i64, enableBan: i32) -> i32; 78 | 79 | /// Haven't been documented. 80 | /// Auth=124 81 | pub fn CQ_setGroupAnonymousBan(AuthCode: i32, groupNum: i64, anonymousName: *const c_char, banTime: i64) -> i32; 82 | 83 | /// Haven't been documented. 84 | /// Auth=125 85 | pub fn CQ_setGroupAnonymous(AuthCode: i32, groupNum: i64, enableAnonymous: i32) -> i32; 86 | 87 | /// Haven't been documented. 88 | /// Auth=126 89 | pub fn CQ_setGroupCard(AuthCode: i32, groupNum: i64, qqNum: i64, nickname: *const c_char) -> i32; 90 | 91 | /// Haven't been documented. 92 | /// Auth=127 93 | pub fn CQ_setGroupLeave(AuthCode: i32, groupNum: i64, disposeGroup: i32) -> i32; 94 | 95 | /// Haven't been documented. 96 | /// Auth=140 97 | pub fn CQ_setDiscussLeave(AuthCode: i32, discussionNum: i64) -> i32; 98 | 99 | /// Haven't been documented. 100 | /// Auth=150 101 | pub fn CQ_setFriendAddRequest(AuthCode: i32, responseFlag: *const c_char, responseType: i32, comment: *const c_char) -> i32; 102 | 103 | /// Haven't been documented. 104 | /// Auth=151 105 | pub fn CQ_setGroupAddRequestV2(AuthCode: i32, responseFlag: *const c_char, requestType: i32, responseType: i32, reason: *const c_char) -> i32; 106 | 107 | /// Haven't been documented. 108 | /// Auth=130 109 | pub fn CQ_getGroupMemberInfoV2(AuthCode: i32, groupNum: i64, qqNum: i64, useCache: i32) -> *const c_char; 110 | 111 | /// Haven't been documented. 112 | /// Auth=160 113 | pub fn CQ_getGroupMemberList(AuthCode: i32, groupNum: i64) -> *const c_char; 114 | 115 | /// Haven't been documented. 116 | /// Auth=161 117 | pub fn CQ_getGroupList(AuthCode: i32) -> *const c_char; 118 | 119 | /// Haven't been documented. 120 | /// Auth=131 121 | pub fn CQ_getStrangerInfo(AuthCode: i32, qqNum: i64, useCache: i32) -> *const c_char; 122 | 123 | /// Prints log in log console. 124 | /// 125 | /// # Examples 126 | /// 127 | /// ``` 128 | /// // let mut c = cqpsdk::Client::new("app_name"); 129 | /// // c.initialize(1); 130 | /// // cqpsdk::cqpapi::CQ_addLog(c.auth_code, cqpsdk::cqpapi::CQLOG_DEBUG, UTF8_STR_TO_GB18030_C_CHAR_PTR!("TAG"), UTF8_STR_TO_GB18030_C_CHAR_PTR!("MSG")); 131 | /// ``` 132 | /// 133 | pub fn CQ_addLog(AuthCode: i32, priority: i32, tag: *const c_char, msg: *const c_char) -> i32; 134 | 135 | 136 | 137 | /// Haven't been documented. 138 | /// Auth=20 139 | pub fn CQ_getCookies(AuthCode: i32) -> *const c_char; 140 | 141 | /// Haven't been documented. 142 | /// Auth=20 143 | pub fn CQ_getCookiesV2(AuthCode: i32) -> *const c_char; 144 | 145 | /// Haven't been documented. 146 | /// Auth=20 147 | pub fn CQ_getCsrfToken(AuthCode: i32) -> i32; 148 | 149 | /// Haven't been documented. 150 | pub fn CQ_getLoginQQ(AuthCode: i32) -> i64; 151 | 152 | /// Haven't been documented. 153 | pub fn CQ_getLoginNick(AuthCode: i32) -> *const c_char; 154 | 155 | /// Haven't been documented. 156 | pub fn CQ_getAppDirectory(AuthCode: i32) -> *const c_char; 157 | 158 | /// Haven't been documented. 159 | pub fn CQ_setFunctionMark(AuthCode: i32, functionName: *const c_char) -> i32; 160 | 161 | /// Haven't been documented. 162 | pub fn CQ_setFatal(AuthCode: i32, errMsg: *const c_char) -> i32; 163 | 164 | /// save audio record to \data\record\ 165 | /// Auth=30 166 | pub fn CQ_getRecord(AuthCode: i32, file: *const c_char, outformat: *const c_char) -> *const c_char; 167 | 168 | } 169 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate base64; 2 | extern crate serde; 3 | #[macro_use] 4 | extern crate serde_derive; 5 | extern crate byteorder; 6 | 7 | extern crate encoding; 8 | use encoding::{Encoding, EncoderTrap}; 9 | use encoding::all::GB18030; 10 | 11 | use std::ffi::{CString, CStr}; 12 | 13 | /// Converts `UTF-8` str to `GB18030` *const i8. 14 | /// 15 | /// Check `CQ_sendPrivateMsg` for examples. 16 | /// 17 | #[macro_export] 18 | macro_rules! UTF8_STR_TO_GB18030_C_CHAR_PTR { 19 | ( $x: expr ) => (CString::new(GB18030.encode($x, EncoderTrap::Ignore).unwrap()).unwrap().into_raw()); 20 | } 21 | 22 | /// Converts `GB18030` *const i8 to `UTF-8` str. 23 | /// 24 | /// An opposite macro against `UTF8_STR_TO_GB18030_C_CHAR_PTR!`. 25 | /// 26 | #[macro_export] 27 | macro_rules! GB18030_C_CHAR_PRT_TO_UTF8_STR { 28 | ( $x: expr ) => (&GB18030.decode(CStr::from_ptr($x).to_bytes(), DecoderTrap::Ignore).unwrap()[..]); 29 | } 30 | 31 | pub mod cqpapi; 32 | pub use cqpapi::base_struct::group::Group; 33 | pub use cqpapi::base_struct::member::Member; 34 | 35 | 36 | pub const API_VERSION:i32=9; 37 | 38 | pub const EVENT_IGNORE: i32 = 0; 39 | pub const EVENT_BLOCK: i32 = 1; 40 | 41 | pub const REQUEST_ALLOW: i32 = 1; 42 | pub const REQUEST_DENY: i32 = 0; 43 | 44 | pub const REQUEST_GROUPADD: i32 = 1; 45 | pub const REQUEST_GROUPINVITEI: i32 = 2; 46 | 47 | pub enum LogLevel{ 48 | Debug = 0, 49 | Info = 10, 50 | InfoSuccess = 11, 51 | InfoRecv = 12, 52 | InfoSend = 13, 53 | Warning = 20, 54 | Error = 30, 55 | Fatal = 40, 56 | } 57 | 58 | impl LogLevel{ 59 | fn to_int(self)->i32{ 60 | match self { 61 | LogLevel::Debug => 0, 62 | LogLevel::Info => 10, 63 | LogLevel::InfoSuccess => 11, 64 | LogLevel::InfoRecv => 12, 65 | LogLevel::InfoSend => 13, 66 | LogLevel::Warning => 20, 67 | LogLevel::Error => 30, 68 | LogLevel::Fatal => 40, 69 | } 70 | } 71 | } 72 | 73 | pub struct Client<'a>{ 74 | auth_code :i32, 75 | initialized :bool, 76 | app_name :&'a str, 77 | api_version :i32 78 | } 79 | 80 | impl<'a> Client<'a>{ 81 | /// Create new Client 82 | /// 83 | /// # Examples 84 | /// 85 | /// ``` 86 | /// let mut c = cqpsdk::Client::new("app_name"); 87 | /// ``` 88 | /// 89 | pub const fn new(app_name:&str) -> Client{ 90 | Client{auth_code:0, initialized:false, app_name:app_name, api_version:API_VERSION} 91 | } 92 | 93 | /// Initialize 94 | /// 95 | /// # Examples 96 | /// 97 | /// ``` 98 | /// let mut c = cqpsdk::Client::new("app_name"); 99 | /// c.initialize(131); 100 | /// ``` 101 | /// 102 | pub fn initialize(&mut self, auth_code: i32){ 103 | self.auth_code = auth_code; 104 | self.initialized = true; 105 | } 106 | 107 | /// Return appinfo 108 | /// 109 | /// # Examples 110 | /// 111 | /// ``` 112 | /// let mut c = cqpsdk::Client::new("app_name"); 113 | /// c.initialize(131); 114 | /// println!("{}", c.app_info()); 115 | /// ``` 116 | /// 117 | pub fn app_info(&self) -> String{ 118 | self.api_version.to_string() + "," + &self.app_name 119 | } 120 | 121 | /// Return login qq no 122 | /// 123 | /// # Examples 124 | /// 125 | /// ``` 126 | /// let mut c = cqpsdk::Client::new("app_name"); 127 | /// c.initialize(131); 128 | /// println!("{}", c.get_login_qq()); 129 | /// ``` 130 | /// 131 | pub fn get_login_qq(&self)->i64{ 132 | unsafe{ 133 | cqpapi::CQ_getLoginQQ(self.auth_code) 134 | } 135 | } 136 | 137 | pub fn send_private_message(&self, qq_number: i64, msg: &str)->i32{ 138 | let msg = UTF8_STR_TO_GB18030_C_CHAR_PTR!(msg); 139 | unsafe{ 140 | cqpapi::CQ_sendPrivateMsg(self.auth_code, qq_number, msg) 141 | } 142 | } 143 | 144 | pub fn add_log(&self, priority: LogLevel, t: &str, msg: &str)->i32{ 145 | let t = UTF8_STR_TO_GB18030_C_CHAR_PTR!(t); 146 | let msg = UTF8_STR_TO_GB18030_C_CHAR_PTR!(msg); 147 | unsafe{ 148 | cqpapi::CQ_addLog(self.auth_code, priority.to_int(), t, msg) 149 | } 150 | } 151 | 152 | pub fn send_group_msg(&self, group_number: i64, msg: &str) -> i32{ 153 | let msg = UTF8_STR_TO_GB18030_C_CHAR_PTR!(msg); 154 | unsafe{ 155 | cqpapi::CQ_sendGroupMsg(self.auth_code, group_number, msg) 156 | } 157 | } 158 | 159 | pub fn send_discussion_msg(&self, discussion_number: i64, msg: &str) -> i32{ 160 | let msg = UTF8_STR_TO_GB18030_C_CHAR_PTR!(msg); 161 | unsafe{ 162 | cqpapi::CQ_sendDiscussMsg(self.auth_code, discussion_number, msg) 163 | } 164 | } 165 | 166 | pub fn send_like(&self, qq_number: i64, times: i32) -> i32{ 167 | unsafe{ 168 | cqpapi::CQ_sendLikeV2(self.auth_code, qq_number, times) 169 | } 170 | } 171 | 172 | pub fn set_group_kick(&self, group_number: i64, qq_number: i64, refuse_rejoin: i32) -> i32{ 173 | unsafe{ 174 | cqpapi::CQ_setGroupKick(self.auth_code, group_number, qq_number, refuse_rejoin) 175 | } 176 | } 177 | 178 | pub fn set_group_ban(&self, group_number: i64, qq_number: i64, ban_time: i64) -> i32{ 179 | unsafe{ 180 | cqpapi::CQ_setGroupBan(self.auth_code, group_number, qq_number, ban_time) 181 | } 182 | } 183 | 184 | pub fn set_group_admin(&self, group_number: i64, qq_number: i64, become_admin: i32) -> i32{ 185 | unsafe{ 186 | cqpapi::CQ_setGroupAdmin(self.auth_code, group_number, qq_number, become_admin) 187 | } 188 | } 189 | 190 | pub fn set_group_whole_ban(&self, group_number: i64, enable_ban: i32) -> i32{ 191 | unsafe{ 192 | cqpapi::CQ_setGroupWholeBan(self.auth_code, group_number, enable_ban) 193 | } 194 | } 195 | 196 | pub fn set_group_anonymous_ban(&self, group_number: i64, anonymous_name: &str, ban_time: i64) -> i32{ 197 | let anonymous_name = UTF8_STR_TO_GB18030_C_CHAR_PTR!(anonymous_name); 198 | unsafe{ 199 | cqpapi::CQ_setGroupAnonymousBan(self.auth_code, group_number, anonymous_name, ban_time) 200 | } 201 | } 202 | 203 | pub fn set_group_anonymous(&self, group_number: i64, enable_anonymous: i32) -> i32{ 204 | unsafe{ 205 | cqpapi::CQ_setGroupAnonymous(self.auth_code, group_number, enable_anonymous) 206 | } 207 | } 208 | 209 | pub fn set_group_card(&self, group_number: i64, qq_number: i64, nickname: &str) -> i32{ 210 | let nickname = UTF8_STR_TO_GB18030_C_CHAR_PTR!(nickname); 211 | unsafe{ 212 | cqpapi::CQ_setGroupCard(self.auth_code, group_number, qq_number, nickname) 213 | } 214 | } 215 | 216 | pub fn set_group_leave(&self, group_number: i64, dispose_group: i32) -> i32{ 217 | unsafe{ 218 | cqpapi::CQ_setGroupLeave(self.auth_code, group_number, dispose_group) 219 | } 220 | } 221 | 222 | pub fn set_group_special_title(&self, group_number: i64, qq_number: i64, title: &str, expire_time: i64) -> i32{ 223 | let title = UTF8_STR_TO_GB18030_C_CHAR_PTR!(title); 224 | unsafe{ 225 | cqpapi::CQ_setGroupSpecialTitle(self.auth_code, group_number, qq_number, title, expire_time) 226 | } 227 | } 228 | 229 | pub fn set_discuss_leave(&self, discussion_number: i64) -> i32{ 230 | unsafe{ 231 | cqpapi::CQ_setDiscussLeave(self.auth_code, discussion_number) 232 | } 233 | } 234 | 235 | pub fn set_friend_add_request(&self, response_flag: &str, response_type: i32, comment: &str) -> i32{ 236 | let response_flag = UTF8_STR_TO_GB18030_C_CHAR_PTR!(response_flag); 237 | let comment = UTF8_STR_TO_GB18030_C_CHAR_PTR!(comment); 238 | unsafe{ 239 | cqpapi::CQ_setFriendAddRequest(self.auth_code, response_flag, response_type, comment) 240 | } 241 | } 242 | 243 | pub fn set_group_add_request(&self, response_flag: &str, request_type: i32, response_type: i32, reason: &str) -> i32{ 244 | let response_flag = UTF8_STR_TO_GB18030_C_CHAR_PTR!(response_flag); 245 | let reason = UTF8_STR_TO_GB18030_C_CHAR_PTR!(reason); 246 | unsafe{ 247 | cqpapi::CQ_setGroupAddRequestV2(self.auth_code, response_flag, request_type, response_type, reason) 248 | } 249 | } 250 | 251 | pub fn get_group_member_info(&self, group_number: i64, qq_number: i64, use_cache: i32) -> Member{ 252 | let rawdata = unsafe{ 253 | CStr::from_ptr(cqpapi::CQ_getGroupMemberInfoV2(self.auth_code, group_number, qq_number, use_cache)).to_str().unwrap() 254 | }; 255 | cqpapi::base_struct::member::Member::parse_to_member(rawdata) 256 | } 257 | 258 | pub fn get_stranger_info(&self, qq_number: i64, use_cache: i32) -> &str{ 259 | unsafe{ 260 | CStr::from_ptr(cqpapi::CQ_getStrangerInfo(self.auth_code, qq_number, use_cache)).to_str().unwrap() 261 | } 262 | } 263 | 264 | pub fn get_cookies(&self) -> &str{ 265 | unsafe{ 266 | CStr::from_ptr(cqpapi::CQ_getCookies(self.auth_code)).to_str().unwrap() 267 | } 268 | } 269 | 270 | pub fn get_csrf_token(&self) -> i32{ 271 | unsafe{ 272 | cqpapi::CQ_getCsrfToken(self.auth_code) 273 | } 274 | } 275 | 276 | pub fn get_login_nick(&self) -> &str{ 277 | unsafe{ 278 | CStr::from_ptr(cqpapi::CQ_getLoginNick(self.auth_code)).to_str().unwrap() 279 | } 280 | } 281 | 282 | pub fn get_app_directory(&self) -> &str{ 283 | unsafe{ 284 | CStr::from_ptr(cqpapi::CQ_getAppDirectory(self.auth_code)).to_str().unwrap() 285 | } 286 | } 287 | 288 | pub fn set_function_mark(&self, function_name: &str) -> i32{ 289 | let function_name = UTF8_STR_TO_GB18030_C_CHAR_PTR!(function_name); 290 | unsafe{ 291 | cqpapi::CQ_setFunctionMark(self.auth_code, function_name) 292 | } 293 | } 294 | 295 | pub fn set_fatal(&self, err_msg: &str) -> i32{ 296 | let err_msg = UTF8_STR_TO_GB18030_C_CHAR_PTR!(err_msg); 297 | unsafe{ 298 | cqpapi::CQ_setFatal(self.auth_code, err_msg) 299 | } 300 | } 301 | 302 | pub fn delete_message(&self, message_id: i64) -> i32{ 303 | unsafe{ 304 | cqpapi::CQ_deleteMsg(self.auth_code, message_id) 305 | } 306 | } 307 | 308 | pub fn get_record(&self, file: &str, outformat: &str) -> &str{ 309 | let file = UTF8_STR_TO_GB18030_C_CHAR_PTR!(file); 310 | let outformat = UTF8_STR_TO_GB18030_C_CHAR_PTR!(outformat); 311 | unsafe{ 312 | CStr::from_ptr(cqpapi::CQ_getRecord(self.auth_code, file, outformat)).to_str().unwrap() 313 | } 314 | } 315 | 316 | pub fn get_group_list(&self) -> Vec{ 317 | let rawdata = unsafe{ 318 | CStr::from_ptr(cqpapi::CQ_getGroupList(self.auth_code)).to_str().unwrap() 319 | }; 320 | cqpapi::base_struct::group::Group::parse_to_group_list(rawdata) 321 | } 322 | 323 | pub fn get_group_member_list(&self, group_number: i64) -> Vec{ 324 | let rawdata = unsafe{ 325 | CStr::from_ptr(cqpapi::CQ_getGroupMemberList(self.auth_code, group_number)).to_str().unwrap() 326 | }; 327 | cqpapi::base_struct::member::Member::parse_to_member_list(rawdata) 328 | } 329 | } 330 | 331 | #[test] 332 | fn cqpclient_new() { 333 | let mut c = Client::new("app_name"); 334 | assert_eq!(c.auth_code, 0); 335 | assert_eq!(c.initialized, false); 336 | assert_eq!(c.api_version, 9); 337 | assert_eq!(c.app_name,"app_name"); 338 | assert_eq!(c.app_info(), "9,app_name"); 339 | c.initialize(131); 340 | assert_eq!(c.auth_code, 131); 341 | assert_eq!(c.initialized, true); 342 | assert_eq!(c.app_info(), "9,app_name"); 343 | } --------------------------------------------------------------------------------