Files
Aurora.3/code/datums/api.dm
Werner 0a2df816c6 API Update (#876)
This adds some useful functions to the API and redefines the way the params are checked.

API Versioning
Very important to be able to check from the client if the serverside API is still compatible with the client implementation
Refactored Params
Mark params as required / optional
Different types of params (string / integer / list / select / senderkey)
Name and description for params
API Function to get all the functions a specific ip/token combo is allowed to use
API Function to get details about a specific API function
2016-09-11 15:53:20 +03:00

905 lines
30 KiB
Plaintext

//
// This file contains the API functions for the serverside API
//
// IMPORTANT:
// When changing api functions always update the version number of the API
// The version number is defined in /datum/topic_command/api_get_version
//Init the API at startup
/hook/startup/proc/setup_api()
for (var/path in typesof(/datum/topic_command) - /datum/topic_command)
var/datum/topic_command/A = new path()
topic_commands[A.name] = A
return 1
//API Boilerplate
/datum/topic_command
var/name = null //Name for the command
var/description = null //Description for the command
var/list/params = list() //Required Parameters for the command
//Explanation of the parameter options:
//Required - name -> Name of the parameter - should be the same as the index in the list
//Required - desc -> Description of the parameter
//Required - req -> Is this a required parameter: 1 -> Yes, 0 -> No
//Required - type -> What type is this:
// str->String,
// int->Integer,
// lst->List/array,
// senderkey->unique identifier of the person sending the request
// slct -> Select one of multiple specified options
//Required* - options -> The possible options that can be selected (slct)
var/statuscode = null
var/response = null
var/data = null
/datum/topic_command/proc/run_command(queryparams)
// Always returns 1 --> Details status in statuscode, response and data
return 1
/datum/topic_command/proc/check_params_missing(queryparams)
//Check if some of the required params are missing
// 0 -> if all params are supplied
// >=1 -> if a param is missing
var/list/missing_params = list()
var/errorcount = 0
for(var/key in params)
var/list/param = params[key]
if(queryparams[key] == null)
if(param["req"] == 0)
log_debug("API: The following parameter is OPTIONAL and missing: [param["name"]] - [param["desc"]]")
else
log_debug("API: The following parameter is REQUIRED but missing: [param["name"]] - [param["desc"]]")
errorcount ++
missing_params += param["name"]
if(errorcount)
log_debug("API: Request aborted. Required parameters missing")
statuscode = 400
response = "Required params missing"
data = missing_params
return errorcount
return 0
//
// API for the API
//
/datum/topic_command/api_get_version
name = "api_get_version"
description = "Gets the version of the API"
/datum/topic_command/api_get_version/run_command(queryparams)
var/list/version = list()
var/versionstring = null
//The Version Number follows SemVer http://semver.org/
version["major"] = 2 //Major Version Number --> Increment when implementing breaking changes
version["minor"] = 0 //Minor Version Number --> Increment when adding features
version["patch"] = 0 //Patchlevel --> Increment when fixing bugs
versionstring = "[version["major"]].[version["minor"]].[version["patch"]]"
statuscode = 200
response = versionstring
data = version
return 1
//Get all the functions a specific token / ip combo is authorized to use
/datum/topic_command/api_get_authed_functions
name = "api_get_authed_functions"
description = "Returns the functions that can be accessed by the requesting ip and token"
/datum/topic_command/api_get_authed_functions/run_command(queryparams)
var/list/functions = list()
//Check if DB Connection is established
if (!establish_db_connection(dbcon))
statuscode = 500
response = "DB Connection Unavailable"
return 1
var/DBQuery/functionsquery = dbcon.NewQuery({"SELECT api_f.function
FROM ss13_api_token_function as api_t_f, ss13_api_tokens as api_t, ss13_api_functions as api_f
WHERE api_t.id = api_t_f.token_id AND api_f.id = api_t_f.function_id
AND (
(token = :token AND ip = :ip)
OR
(token = :token AND ip IS NULL)
OR
(token IS NULL AND ip = :ip)
)"})
functionsquery.Execute(list(":token" = queryparams["auth"], ":ip" = queryparams["addr"]))
while (functionsquery.NextRow())
functions[functionsquery.item[1]] = functionsquery.item[1]
statuscode = 200
response = "Authorized functions retrieved"
data = functions
return 1
//Get details for a specific api function
/datum/topic_command/api_explain_function
name = "api_explain_function"
description = "Explains a specific API function"
params = list(
"function" = list("name"="function","desc"="The name of the API function that should be explained","req"=1,"type"="str")
)
/datum/topic_command/api_explain_function/run_command(queryparams)
var/datum/topic_command/apifunction = topic_commands[queryparams["function"]]
var/list/functiondata = list()
if (isnull(apifunction))
statuscode = 501
response = "Not Implemented - The requested function does not exist"
return 1
//Then query for auth
if (!establish_db_connection(dbcon))
statuscode = 500
response = "DB Connection Unavailable"
return 1
var/DBQuery/permquery = dbcon.NewQuery({"SELECT api_f.function
FROM ss13_api_token_function as api_t_f, ss13_api_tokens as api_t, ss13_api_functions as api_f
WHERE api_t.id = api_t_f.token_id AND api_f.id = api_t_f.function_id
AND api_t.deleted_at IS NULL
AND (
(token = :token AND ip = :ip AND function = :function)
OR
(token = :token AND ip IS NULL AND function = :function)
OR
(token = :token AND ip = :ip AND function = \"ANY\")
OR
(token = :token AND ip IS NULL AND function = \"ANY\")
OR
(token IS NULL AND ip IS NULL AND function = :function)
)"})
//Get the tokens and the associated functions
//Check if the token, the ip and the function matches OR
// the token + function matches and the ip is NULL (Functions that can be used by any ip, but require a token)
// the token + ip matches and the function is NULL (Allow a specific ip with a specific token to use all functions)
// the token + ip is NULL and the function matches (Allow a specific function to be used without auth)
permquery.Execute(list(":token" = queryparams["auth"], ":ip" = queryparams["addr"], ":function" = queryparams["function"]))
if (!permquery.RowCount())
statuscode = 401
response = "Unauthorized - To access this function"
return 1
functiondata["name"] = apifunction.name
functiondata["description"] = apifunction.description
functiondata["params"] = apifunction.params
statuscode = 200
response = "Function data retrieved"
data = functiondata
return 1
//
// API for the other stuff
//
//Char Names
/datum/topic_command/get_char_list
name = "get_char_list"
description = "Provides a list of all characters ingame"
/datum/topic_command/get_char_list/run_command(queryparams)
if (!ticker)
statuscode = 500
response = "Game not started yet!"
return 1
var/list/chars = list()
var/list/mobs = sortmobs()
for(var/mob/M in mobs)
if(!M.ckey) continue
chars[M.name] += M.key ? (M.client ? M.key : "[M.key] (DC)") : "No key"
statuscode = 200
response = "Char list fetched"
data = chars
return 1
//Admin Count
/datum/topic_command/get_count_admin
name = "get_count_admin"
description = "Gets the number of admins connected"
/datum/topic_command/get_count_admin/run_command(queryparams)
var/n = 0
for (var/client/client in clients)
if (client.holder && client.holder.rights & (R_ADMIN))
n++
statuscode = 200
response = "Admin count fetched"
data = n
return 1
//CCIA Count
/datum/topic_command/get_count_cciaa
name = "get_count_cciaa"
description = "Gets the number of ccia connected"
/datum/topic_command/get_count_ccia/run_command(queryparams)
var/n = 0
for (var/client/client in clients)
if (client.holder && (client.holder.rights & R_CCIAA) && !(client.holder.rights & R_ADMIN))
n++
statuscode = 200
response = "CCIA count fetched"
data = n
return 1
//Mod Count
/datum/topic_command/get_count_mod
name = "get_count_mod"
description = "Gets the number of mods connected"
/datum/topic_command/get_count_mod/run_command(queryparams)
var/n = 0
for (var/client/client in clients)
if (client.holder && (client.holder.rights & R_MOD) && !(client.holder.rights & R_ADMIN))
n++
statuscode = 200
response = "Mod count fetched"
data = n
return 1
//Player Count
/datum/topic_command/get_count_player
name = "get_count_player"
description = "Gets the number of players connected"
/datum/topic_command/get_count_player/run_command(queryparams)
var/n = 0
for(var/mob/M in player_list)
if(M.client)
n++
statuscode = 200
response = "Player count fetched"
data = n
return 1
//Get available Fax Machines
/datum/topic_command/get_faxmachines
name = "get_faxmachines"
description = "Gets all available fax machines"
/datum/topic_command/get_faxmachines/run_command(queryparams)
var/list/faxlocations = list()
for (var/obj/machinery/photocopier/faxmachine/F in allfaxes)
faxlocations.Add(F.department)
statuscode = 200
response = "Fax machines fetched"
data = faxlocations
return 1
//Get Fax List
/datum/topic_command/get_faxlist
name = "get_faxlist"
description = "Gets the list of faxes sent / received"
params = list(
"faxtype" = list("name"="faxtype","desc"="Type of the faxes that should be retrieved","req"=1,"type"="slct","options"=list("sent","received"))
)
/datum/topic_command/get_faxlist/run_command(queryparams)
if (!ticker)
statuscode = 500
response = "Round hasn't started yet! No faxes to display!"
data = null
return 1
var/list/faxes = list()
switch (queryparams["faxtype"])
if ("received")
faxes = arrived_faxes
if ("sent")
faxes = sent_faxes
if (!faxes || !faxes.len)
statuscode = 404
response = "No faxes found"
data = null
return 1
var/list/output = list()
for (var/i = 1, i <= faxes.len, i++)
var/obj/item/a = faxes[i]
output += "[i]"
output[i] = a.name ? a.name : "Untitled Fax"
statuscode = 200
response = "Fetched Fax List"
data = output
return 1
//Get Specific Fax
/datum/topic_command/get_fax
name = "get_fax"
description = "Gets a specific fax that has been sent or received"
params = list(
"faxtype" = list("name"="faxtype","desc"="Type of the faxes that should be retrieved","req"=1,"type"="slct","options"=list("sent","received")),
"faxid" = list("name"="faxid","desc"="ID of the fax that should be retrieved","req"=1,"type"="int")
)
/datum/topic_command/get_fax/run_command(queryparams)
var/list/faxes = list()
switch (queryparams["faxtype"])
if ("received")
faxes = arrived_faxes
if ("sent")
faxes = sent_faxes
if (!faxes || !faxes.len)
statuscode = 500
response = "No faxes found!"
data = null
return 1
var/fax_id = text2num(queryparams["faxid"])
if (fax_id > faxes.len || fax_id < 1)
statuscode = 404
response = "Invalid Fax ID"
data = null
return 1
var/output = list()
if (istype(faxes[fax_id], /obj/item/weapon/paper))
var/obj/item/weapon/paper/a = faxes[fax_id]
output["title"] = a.name ? a.name : "Untitled Fax"
var/content = replacetext(a.info, "<br>", "\n")
content = strip_html_properly(content, 0)
output["content"] = content
statuscode = 200
response = "Fax (Paper) with id [fax_id] retrieved"
data = output
return 1
else if (istype(faxes[fax_id], /obj/item/weapon/photo))
statuscode = 501
response = "Fax is a Photo - Unable to send"
data = null
return 1
else if (istype(faxes[fax_id], /obj/item/weapon/paper_bundle))
var/obj/item/weapon/paper_bundle/b = faxes[fax_id]
output["title"] = b.name ? b.name : "Untitled Paper Bundle"
if (!b.pages || !b.pages.len)
statuscode = 500
response = "Fax Paper Bundle is empty - This should not happen"
data = null
return 1
var/i = 0
for (var/obj/item/weapon/paper/c in b.pages)
i++
var/content = replacetext(c.info, "<br>", "\n")
content = strip_html_properly(content, 0)
output["content"] += "Page [i]:\n[content]\n\n"
statuscode = 200
response = "Fax (PaperBundle) retrieved"
data = output
return 1
statuscode = 500
response = "Unable to recognize the fax type. Cannot send contents!"
data = null
return 1
//Get Ghosts
/datum/topic_command/get_ghosts
name = "get_ghosts"
description = "Gets the ghosts"
/datum/topic_command/get_ghosts/run_command(queryparams)
var/list/ghosts[] = list()
ghosts = get_ghosts(1,1)
statuscode = 200
response = "Fetched Ghost list"
data = ghosts
return 1
// Crew Manifest
/datum/topic_command/get_manifest
name = "get_manifest"
description = "Gets the crew manifest"
/datum/topic_command/get_manifest/run_command(queryparams)
if (!ticker)
statuscode = 500
response = "Game not started yet!"
return 1
var/list/positions = list()
var/list/set_names = list(
"heads" = command_positions,
"sec" = security_positions,
"eng" = engineering_positions,
"med" = medical_positions,
"sci" = science_positions,
"civ" = civilian_positions,
"bot" = nonhuman_positions
)
for(var/datum/data/record/t in data_core.general)
var/name = t.fields["name"]
var/rank = t.fields["rank"]
var/real_rank = make_list_rank(t.fields["real_rank"])
var/department = 0
for(var/k in set_names)
if(real_rank in set_names[k])
if(!positions[k])
positions[k] = list()
positions[k][name] = rank
department = 1
if(!department)
if(!positions["misc"])
positions["misc"] = list()
positions["misc"][name] = rank
// for(var/k in positions)
// positions[k] = list2params(positions[k]) // converts positions["heads"] = list("Bob"="Captain", "Bill"="CMO") into positions["heads"] = "Bob=Captain&Bill=CMO"
statuscode = 200
response = "Manifest fetched"
data = positions
return 1
//Player Ckeys
/datum/topic_command/get_player_list
name = "get_player_list"
description = "Gets a list of connected players"
/datum/topic_command/get_player_list/run_command(queryparams)
var/list/players = list()
for (var/client/C in clients)
players += C.key
statuscode = 200
response = "Player list fetched"
data = players
return 1
//Get info about a specific player
/datum/topic_command/get_player_info
name = "get_player_info"
description = "Gets information about a specific player"
params = list(
"search" = list("name"="search","desc"="List with strings that should be searched for","req"=1,"type"="lst")
)
/datum/topic_command/get_player_info/run_command(queryparams)
var/list/search = queryparams["search"]
var/list/ckeysearch = list()
for(var/text in search)
ckeysearch += ckey(text)
var/list/match = list()
for(var/mob/M in mob_list)
var/strings = list(M.name, M.ckey)
if(M.mind)
strings += M.mind.assigned_role
strings += M.mind.special_role
for(var/text in strings)
if(ckey(text) in ckeysearch)
match[M] += 10 // an exact match is far better than a partial one
else
for(var/searchstr in search)
if(findtext(text, searchstr))
match[M] += 1
var/maxstrength = 0
for(var/mob/M in match)
maxstrength = max(match[M], maxstrength)
for(var/mob/M in match)
if(match[M] < maxstrength)
match -= M
if(!match.len)
statuscode = 449
response = "No match found"
data = null
return 1
else if(match.len == 1)
var/mob/M = match[1]
var/info = list()
info["key"] = M.key
if (M.client)
var/client/C = M.client
info["discordmuted"] = C.mute_discord ? "Yes" : "No"
info["name"] = M.name == M.real_name ? M.name : "[M.name] ([M.real_name])"
info["role"] = M.mind ? (M.mind.assigned_role ? M.mind.assigned_role : "No role") : "No mind"
var/turf/MT = get_turf(M)
info["loc"] = M.loc ? "[M.loc]" : "null"
info["turf"] = MT ? "[MT] @ [MT.x], [MT.y], [MT.z]" : "null"
info["area"] = MT ? "[MT.loc]" : "null"
info["antag"] = M.mind ? (M.mind.special_role ? M.mind.special_role : "Not antag") : "No mind"
info["hasbeenrev"] = M.mind ? M.mind.has_been_rev : "No mind"
info["stat"] = M.stat
info["type"] = M.type
if(isliving(M))
var/mob/living/L = M
info["damage"] = list2params(list(
oxy = L.getOxyLoss(),
tox = L.getToxLoss(),
fire = L.getFireLoss(),
brute = L.getBruteLoss(),
clone = L.getCloneLoss(),
brain = L.getBrainLoss()
))
else
info["damage"] = "non-living"
info["gender"] = M.gender
statuscode = 200
response = "Client data fetched"
data = info
return 1
else
statuscode = 449
response = "Multiple Matches found"
data = null
return 1
//Get Server Status
/datum/topic_command/get_serverstatus
name = "get_serverstatus"
description = "Gets the serverstatus"
/datum/topic_command/get_serverstatus/run_command(queryparams)
var/list/s[] = list()
s["version"] = game_version
s["mode"] = master_mode
s["respawn"] = config.abandon_allowed
s["enter"] = config.enter_allowed
s["vote"] = config.allow_vote_mode
s["ai"] = config.allow_ai
s["host"] = host ? host : null
s["players"] = 0
s["stationtime"] = worldtime2text()
s["roundduration"] = round_duration()
if(queryparams["status"] == "2")
var/list/players = list()
var/list/admins = list()
for(var/client/C in clients)
if(C.holder)
if(C.holder.fakekey)
continue
admins[C.key] = C.holder.rank
players += C.key
s["players"] = players.len
s["playerlist"] = list2params(players)
s["admins"] = admins.len
s["adminlist"] = list2params(admins)
else
var/n = 0
var/admins = 0
for(var/client/C in clients)
if(C.holder)
if(C.holder.fakekey)
continue //so stealthmins aren't revealed by the hub
admins++
s["player[n]"] = C.key
n++
s["players"] = n
s["admins"] = admins
statuscode = 200
response = "Server Status fetched"
data = s
return 1
//Get a Staff List
/datum/topic_command/get_stafflist
name = "get_stafflist"
description = "Gets a list of connected staffmembers"
/datum/topic_command/get_stafflist/run_command(queryparams)
var/list/staff = list()
for (var/client/C in admins)
staff[C] = C.holder.rank
statuscode = 200
response = "Staff list fetched"
data = staff
return 1
//Grant Respawn
/datum/topic_command/grant_respawn
name = "grant_respawn"
description = "Grants a respawn to a specific target"
params = list(
"senderkey" = list("name"="senderkey","desc"="Unique id of the person that authorized the respawn","req"=1,"type"="senderkey"),
"target" = list("name"="target","desc"="Ckey of the target that should be granted a respawn","req"=1,"type"="str")
)
/datum/topic_command/grant_respawn/run_command(queryparams)
var/list/ghosts = get_ghosts(1,1)
var/target = queryparams["target"]
var/allow_antaghud = queryparams["allow_antaghud"]
var/senderkey = queryparams["senderkey"] //Identifier of the sender (Ckey / Userid / ...)
var/mob/dead/observer/G = ghosts[target]
if(!G in ghosts)
statuscode = 404
response = "Target not in ghosts list"
data = null
return 1
if(G.has_enabled_antagHUD && config.antag_hud_restricted && allow_antaghud == 0)
statuscode = 409
response = "Ghost has used Antag Hud - Respawn Aborted"
data = null
return 1
G.timeofdeath=-19999 /* time of death is checked in /mob/verb/abandon_mob() which is the Respawn verb.
timeofdeath is used for bodies on autopsy but since we're messing with a ghost I'm pretty sure
there won't be an autopsy.
*/
var/datum/preferences/P
if (G.client)
P = G.client.prefs
else if (G.ckey)
P = preferences_datums[G.ckey]
else
statuscode = 500
response = "Something went wrong, couldn't find the target's preferences datum"
data = null
return 1
for (var/entry in P.time_of_death)//Set all the prefs' times of death to a huge negative value so any respawn timers will be fine
P.time_of_death[entry] = -99999
G.has_enabled_antagHUD = 2
G.can_reenter_corpse = 1
G:show_message(text("\blue <B>You may now respawn. You should roleplay as if you learned nothing about the round during your time with the dead.</B>"), 1)
log_admin("[senderkey] allowed [key_name(G)] to bypass the 30 minute respawn limit via the API")
message_admins("Admin [senderkey] allowed [key_name_admin(G)] to bypass the 30 minute respawn limit via the API", 1)
statuscode = 200
response = "Respawn Granted"
data = null
return 1
//Ping Test
/datum/topic_command/ping
name = "ping"
description = "API test command"
/datum/topic_command/ping/run_command(queryparams)
var/x = 1
for (var/client/C)
x++
statuscode = 200
response = "Pong"
data = x
return 1
//Restart Round
/datum/topic_command/restart_round
name = "restart_round"
description = "Restarts the round"
params = list(
"senderkey" = list("name"="senderkey","desc"="Unique id of the person that authorized the restart","req"=1,"type"="senderkey")
)
/datum/topic_command/restart_round/run_command(queryparams)
var/senderkey = sanitize(queryparams["senderkey"]) //Identifier of the sender (Ckey / Userid / ...)
world << "<font size=4 color='#ff2222'>Server restarting by remote command.</font>"
log_and_message_admins("World restart initiated remotely by [senderkey].")
feedback_set_details("end_error","remote restart")
if (blackbox)
blackbox.save_all_data_to_sql()
spawn(50)
log_game("Rebooting due to remote command.")
world.Reboot(10)
statuscode = 200
response = "Restart Command accepted"
data = null
return 1
//Get available Fax Machines
/datum/topic_command/send_adminmsg
name = "send_adminmsg"
description = "Sends a adminmessage to a player"
params = list(
"ckey" = list("name"="ckey","desc"="The target of the adminmessage","req"=1,"type"="str"),
"msg" = list("name"="msg","desc"="The message that should be sent","req"=1,"type"="str"),
"senderkey" = list("name"="senderkey","desc"="Unique id of the person that sent the adminmessage","req"=1,"type"="senderkey"),
"rank" = list("name"="rank","desc"="The rank that should be displayed - Defaults to admin if none specified","req"=0,"type"="str"),
)
/datum/topic_command/send_adminmsg/run_command(queryparams)
/*
We got an adminmsg from IRC bot lets split the API
expected output:
1. ckey = ckey of person the message is to
2. msg = contents of message, parems2list requires
3. rank = Rank that should be displayed
4. senderkey = the ircnick that send the message.
*/
var/client/C
var/req_ckey = ckey(queryparams["ckey"])
for(var/client/K in clients)
if(K.ckey == req_ckey)
C = K
break
if(!C)
statuscode = 404
response = "No client with that name on server"
data = null
return 1
var/rank = queryparams["rank"]
if(!rank)
rank = "Admin"
var/message = "<font color='red'>[rank] PM from <b><a href='?discord_msg=[queryparams["senderkey"]]'>[queryparams["senderkey"]]</a></b>: [queryparams["msg"]]</font>"
var/amessage = "<font color='blue'>[rank] PM from <a href='?discord_msg=[queryparams["senderkey"]]'>[queryparams["senderkey"]]</a> to <b>[key_name(C)]</b> : [queryparams["msg"]]</font>"
C.received_discord_pm = world.time
C.discord_admin = queryparams["senderkey"]
C << 'sound/effects/adminhelp.ogg'
C << message
for(var/client/A in admins)
if(A != C)
A << amessage
statuscode = 200
response = "Admin Message sent"
data = null
return 1
//Send a Command Report
/datum/topic_command/send_commandreport
name = "send_commandreport"
description = "Sends a command report"
params = list(
"senderkey" = list("name"="senderkey","desc"="Unique id of the person that sent the commandreport","req"=1,"type"="senderkey"),
"title" = list("name"="title","desc"="The message title that should be sent, Defaults to NanoTrasen Update if not specified","req"=0,"type"="str"),
"body" = list("name"="body","desc"="The message body that should be sent","req"=1,"type"="str"),
"type" = list("name"="type","desc"="The type of the message that should be sent, Defaults to freeform","req"=0,"type"="slct","options"=list("freeform","ccia")),
"sendername" = list("name"="sendername","desc"="IC Name of the sender for the CCIA Report, Defaults to CCIAAMS, \[Command-StationName\]","req"=0,"type"="string"),
"announce" = list("name"="announce","desc"="If the report should be announce 1 -> Yes, 0 -> No, Defaults to 1","req"=0,"type"="int")
)
/datum/topic_command/send_commandreport/run_command(queryparams)
var/senderkey = sanitize(queryparams["senderkey"]) //Identifier of the sender (Ckey / Userid / ...)
var/reporttitle = sanitizeSafe(queryparams["title"]) //Title of the report
var/reportbody = sanitize(queryparams["body"]) //Body of the report
var/reporttype = queryparams["type"] //Type of the report: freeform / ccia / admin
var/reportsender = sanitize(queryparams["sendername"]) //Name of the sender
var/reportannounce = queryparams["announce"] //Announce the contents report to the public: 1 / 0
if(!reporttitle)
reporttitle = "NanoTrasen Update"
if(!reporttype)
reporttype = "freeform"
if(!reportannounce)
reportannounce = 1
//Send the message to the communications consoles
for (var/obj/machinery/computer/communications/C in machines)
if(! (C.stat & (BROKEN|NOPOWER) ) )
var/obj/item/weapon/paper/P = new /obj/item/weapon/paper( C.loc )
P.name = "[command_name()] Update"
P.info = replacetext(reportbody, "\n", "<br/>")
P.update_space(P.info)
P.update_icon()
C.messagetitle.Add("[command_name()] Update")
C.messagetext.Add(P.info)
//Set the report footer for CCIA Announcements
if (reporttype == "ccia")
if (reportsender)
reportbody += "<br/><br/>- [reportsender], Central Command Internal Affairs Agent, [commstation_name()]"
else
reportbody += "<br/><br/>- CCIAAMS, [commstation_name()]"
if(reportannounce == 1)
command_announcement.Announce(reportbody, reporttitle, new_sound = 'sound/AI/commandreport.ogg', msg_sanitized = 1);
if(reportannounce == 0)
world << "\red New NanoTrasen Update available at all communication consoles."
world << sound('sound/AI/commandreport.ogg')
log_admin("[senderkey] has created a command report via the api: [reportbody]")
message_admins("[senderkey] has created a command report via the api", 1)
statuscode = 200
response = "Command Report sent"
data = null
return 1
//Send Fax
/datum/topic_command/send_fax
name = "send_fax"
description = "Sends a fax"
params = list(
"senderkey" = list("name"="senderkey","desc"="Unique id of the person that sent the fax","req"=1,"type"="senderkey"),
"title" = list("name"="title","desc"="The message title that should be sent","req"=1,"type"="str"),
"body" = list("name"="body","desc"="The message body that should be sent","req"=1,"type"="str"),
"target" = list("name"="target","desc"="The target faxmachines the fax should be sent to","req"=1,"type"="lst")
)
/datum/topic_command/send_fax/run_command(queryparams)
var/list/responselist = list()
var/list/sendsuccess = list()
var/list/targetlist = queryparams["target"] //Target locations where the fax should be sent to
var/senderkey = sanitize(queryparams["senderkey"]) //Identifier of the sender (Ckey / Userid / ...)
var/faxtitle = sanitizeSafe(queryparams["title"]) //Title of the report
var/faxbody = sanitize(queryparams["body"]) //Body of the report
var/faxannounce = queryparams["announce"] //Announce the contents report to the public: 1 / 0
if(!targetlist || targetlist.len < 1)
statuscode = 400
response = "Parameter target not set"
data = null
return 1
if(!faxannounce)
faxannounce = 1
var/sendresult = 0
//Send the fax
for (var/obj/machinery/photocopier/faxmachine/F in allfaxes)
if (F.department in targetlist)
sendresult = send_fax(F, faxtitle, faxbody, senderkey)
if (sendresult == 1)
sendsuccess.Add(F.department)
responselist[F.department] = "success"
else
responselist[F.department] = "failed"
//Announce that the fax has been sent
if(faxannounce == 1)
if(sendsuccess.len < 1)
command_announcement.Announce("A fax message from Central Command could not be delivered because all of the following fax machines are inoperational: <br>"+list2text(targetlist, ", "), "Fax Received", new_sound = 'sound/AI/commandreport.ogg', msg_sanitized = 1);
else
command_announcement.Announce("A fax message from Central Command has been sent to the following fax machines: <br>"+list2text(sendsuccess, ", "), "Fax Received", new_sound = 'sound/AI/commandreport.ogg', msg_sanitized = 1);
log_admin("[senderkey] sent a fax via the API: : [faxbody]")
message_admins("[senderkey] sent a fax via the API", 1)
statuscode = 200
response = "Fax sent"
data = responselist
return 1
/datum/topic_command/send_fax/proc/send_fax(var/obj/machinery/photocopier/faxmachine/F, title, body, senderkey)
// Create the reply message
var/obj/item/weapon/paper/P = new /obj/item/weapon/paper( null ) //hopefully the null loc won't cause trouble for us
P.name = "[command_name()] - [title]"
P.info = body
P.update_icon()
// Stamps
var/image/stampoverlay = image('icons/obj/bureaucracy.dmi')
stampoverlay.icon_state = "paper_stamp-cent"
if(!P.stamped)
P.stamped = new
P.stamped += /obj/item/weapon/stamp
P.overlays += stampoverlay
P.stamps += "<HR><i>This paper has been stamped by the Central Command Quantum Relay.</i>"
if(F.recievefax(P))
log_and_message_admins("[senderkey] sent a fax message to the [F.department] fax machine via the api. (<A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[F.x];Y=[F.y];Z=[F.z]'>JMP</a>)")
sent_faxes += P
return 1
else
qdel(P)
return 2