mirror of
https://github.com/nzp-team/fteqw.git
synced 2024-11-25 21:31:37 +00:00
696c7e8260
some more tweaks for xonotic rcon-over-xmpp, because I can. Server might see your rcon password, so watch out for that. qcc tweaks. updated q1qvm api stuff to api version 15. android port updated. egl now handled by native code, which means we now have proper control over everything and can default to gles2. requires android 2.0+. vulkan-on-android renderer added, but not tested. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5153 fc73d0e0-1445-4013-8a0c-d673dee63da5
359 lines
12 KiB
C
359 lines
12 KiB
C
#include "../plugin.h"
|
|
|
|
#include "xml.h"
|
|
|
|
|
|
//configuration
|
|
|
|
//#define NOICE //if defined, we only do simple raw udp connections.
|
|
#define FILETRANSFERS //IBB only, speeds suck. autoaccept is forced on. no protection from mods stuffcmding sendfile commands. needs more extensive testing
|
|
#define QUAKECONNECT //including quake ICE connections (depends upon jingle)
|
|
#define VOIP //enables voice chat (depends upon jingle)
|
|
//#define VOIP_LEGACY //enables google-only voice chat compat. google have not kept up with the standardisation of jingle (aka: gingle).
|
|
//#define VOIP_LEGACY_ONLY //disables jingle feature (advert+detection only)
|
|
#define JINGLE //enables jingle signalling
|
|
|
|
#ifdef JINGLE
|
|
#include "../../engine/common/netinc.h"
|
|
#else
|
|
#undef VOIP
|
|
#undef VOIP_LEGACY
|
|
#endif
|
|
|
|
|
|
#define JCL_BUILD "5"
|
|
//#define DEFAULTDOMAIN "triptohell.info"
|
|
#define DEFAULTRESOURCE "Quake"
|
|
#define QUAKEMEDIAXMLNS "http://fteqw.com/protocol/quake"
|
|
#define DISCONODE "http://fteqw.com/ftexmpp" //some sort of client identifier
|
|
#define DEFAULTICEMODE ICEM_ICE
|
|
|
|
#define MEDIATYPE_QUAKE "quake"
|
|
#define MEDIATYPE_VIDEO "video"
|
|
#define MEDIATYPE_AUDIO "audio"
|
|
|
|
|
|
|
|
#define JCL_MAXMSGLEN 0x10000
|
|
|
|
//values are not on the wire or anything
|
|
#define CAP_VOICE (1u<<0) //supports voice
|
|
#define CAP_GOOGLE_VOICE (1u<<1) //google supports some old non-standard version of jingle.
|
|
#define CAP_VIDEO (1u<<2) //supports video calls
|
|
|
|
#define CAP_GAMEINVITE (1u<<3) //supports game invites. custom/private protocol
|
|
#define CAP_POKE (1u<<4) //can be slapped.
|
|
#define CAP_SIFT (1u<<5) //non-jingle file transfers
|
|
#define CAP_AVATARS (1u<<6) //can enable querying for user avatars, but cannot disable advertising our own.
|
|
|
|
//not actually capabilities, but just down to how we handle querying them.
|
|
#define CAP_QUERYING (1u<<29) //we've sent a query and are waiting for the response.
|
|
#define CAP_QUERIED (1u<<30) //feature capabilities are actually know.
|
|
#define CAP_QUERYFAILED (1u<<31) //caps request failed due to bad hash or some such.
|
|
|
|
//features that default to disabled.
|
|
#define CAP_DEFAULTENABLEDCAPS (CAP_VOICE/*|CAP_VIDEO*/|CAP_GAMEINVITE|CAP_POKE|CAP_AVATARS/*|CAP_SIFT*/|CAP_GOOGLE_VOICE)
|
|
|
|
typedef struct bresource_s
|
|
{
|
|
char bstatus[128]; //basic status
|
|
char fstatus[128]; //full status
|
|
char server[256];
|
|
int servertype; //0=none, 1=already a client, 2=joinable
|
|
int priority;
|
|
|
|
unsigned int buggycaps;
|
|
unsigned int caps;
|
|
char *client_node; //vendor name
|
|
char *client_ver; //cap hash value
|
|
char *client_hash; //cap hash method
|
|
char *client_ext; //deprecated. additionally queried
|
|
|
|
struct bresource_s *next;
|
|
|
|
char resource[1];
|
|
} bresource_t;
|
|
typedef struct buddy_s
|
|
{
|
|
bresource_t *resources;
|
|
bresource_t *defaultresource; //this is the one that last replied (must be null for chatrooms, so we only talk to the room in general)
|
|
bresource_t *ourselves; //this is set back to ourselves when in a chatroom
|
|
int defaulttimestamp;
|
|
qboolean askfriend;
|
|
qboolean friended;
|
|
qboolean vcardphotochanged;
|
|
enum {
|
|
BT_UNKNOWN, //this buddy isn't known...
|
|
BT_ROSTER, //this is a friend! or at least on our list of potential friends anyway.
|
|
BT_CHATROOM //we're treating this 'guy' as a MUC, each of their resources is a different person. which is weird.
|
|
} btype;
|
|
|
|
qboolean room_autojoin;
|
|
char *room_nick;
|
|
char *room_password;
|
|
char *room_topic;
|
|
|
|
char name[256];
|
|
char vcardphotohash[41];
|
|
qhandle_t image;
|
|
|
|
struct buddy_s *next;
|
|
char accountdomain[1]; //no resource on there
|
|
} buddy_t;
|
|
typedef struct jclient_s
|
|
{
|
|
int accountnum; //a private id to track which client links are associated with
|
|
|
|
char redirserveraddr[64]; //if empty, do an srv lookup.
|
|
|
|
enum
|
|
{
|
|
JCL_INACTIVE, //not trying to connect.
|
|
JCL_DEAD, //not connected. connection died or something.
|
|
JCL_AUTHING, //connected, but not able to send any info on it other than to auth
|
|
JCL_ACTIVE //we're connected, we got a buddy list and everything
|
|
} status;
|
|
unsigned int timeout; //reconnect/ping timer
|
|
char errormsg[256];
|
|
|
|
unsigned int enabledcapabilities;
|
|
|
|
qhandle_t socket;
|
|
|
|
qhandle_t rcon_pipe; //contains console prints
|
|
char rcon_peer[256]; //the name of the guy currently receiving console prints
|
|
|
|
//we buffer output for times when the outgoing socket is full.
|
|
//mostly this only happens at the start of the connection when the socket isn't actually open yet.
|
|
char *outbuf;
|
|
int outbufpos;
|
|
int outbuflen;
|
|
int outbufmax;
|
|
|
|
char bufferedinmessage[JCL_MAXMSGLEN+1]; //servers are required to be able to handle messages no shorter than a specific size.
|
|
//which means we need to be able to handle messages when they get to us.
|
|
//servers can still handle larger messages if they choose, so this might not be enough.
|
|
int bufferedinammount;
|
|
|
|
char defaultdest[256];
|
|
|
|
//config info
|
|
char serveraddr[64]; //if empty, do an srv lookup.
|
|
int serverport;
|
|
char domain[256];
|
|
char username[256];
|
|
char resource[256];
|
|
char certificatedomain[256];
|
|
int forcetls; //-1=off, 0=ifpossible, 1=fail if can't upgrade, 2=old-style tls
|
|
qboolean savepassword;
|
|
|
|
char fulljid[256]; //this is our full username@domain/resource string
|
|
char barejid[256]; //this is our bare username@domain string
|
|
char localalias[256];//this is what's shown infront of outgoing messages. >> by default until we can get our name.
|
|
char vcardphotohash[20]; //20-byte sha1 hash.
|
|
enum
|
|
{
|
|
VCP_UNKNOWN,
|
|
VCP_NONE,
|
|
VCP_KNOWN
|
|
} vcardphotohashstatus;
|
|
qboolean vcardphotohashchanged; //forces a presence send.
|
|
|
|
int instreampos;
|
|
|
|
qboolean connecting; //still waiting for intial stream tag
|
|
qboolean connected; //fully on server and authed and everything.
|
|
qboolean issecure; //tls enabled (either upgraded or initially)
|
|
int streamdebug; //echo the stream to subconsoles
|
|
|
|
qboolean preapproval; //server supports presence preapproval
|
|
|
|
char curquakeserver[2048];
|
|
char defaultnamespace[2048]; //should be 'jabber:client' or blank (and spammy with all the extra xmlns attribs)
|
|
|
|
struct sasl_ctx_s
|
|
{
|
|
char *username; //might be different from the account name, but probably isn't.
|
|
char *domain; //might be different from the account domain, but probably isn't.
|
|
qboolean issecure; //tls enabled (either upgraded or initially)
|
|
int socket;
|
|
|
|
//this stuff should be saved
|
|
char password_plain[256]; //plain password. scrubbed if we auth using a hashed auth.
|
|
qbyte password_hash[256]; //safer password, not encrypted, but stored hashed.
|
|
size_t password_hash_size;
|
|
char password_validity[256]; //internal string used to check that the salt was unchanged
|
|
|
|
struct saslmethod_s *authmethod; //null name = oauth2->saslmethod
|
|
qboolean allowauth_plainnontls; //allow plain plain
|
|
qboolean allowauth_plaintls; //allow tls plain
|
|
qboolean allowauth_digestmd5; //allow digest-md5 auth
|
|
qboolean allowauth_scramsha1; //allow scram-sha-1 auth
|
|
qboolean allowauth_oauth2; //use oauth2 where possible
|
|
|
|
struct
|
|
{
|
|
char authnonce[256];
|
|
} digest;
|
|
|
|
struct
|
|
{
|
|
qboolean plus;
|
|
char authnonce[256];
|
|
char authvhash[20];
|
|
char authcbindtype[20];
|
|
char authcbinding[256];
|
|
hashfunc_t *hashfunc;
|
|
size_t hashsize;
|
|
} scram;
|
|
|
|
struct
|
|
{
|
|
char saslmethod[64];
|
|
char obtainurl[256];
|
|
char refreshurl[256];
|
|
char clientid[256];
|
|
char clientsecret[256];
|
|
char *useraccount;
|
|
char *scope;
|
|
char *accesstoken; //one-shot access token
|
|
char *refreshtoken; //long-term token that we can use to get new access tokens
|
|
char *authtoken; //short-term authorisation token, usable to get an access token (and a refresh token if we're lucky)
|
|
} oauth2;
|
|
} sasl;
|
|
|
|
struct iq_s
|
|
{
|
|
struct iq_s *next;
|
|
char id[64];
|
|
int timeout;
|
|
qboolean (*callback) (struct jclient_s *jcl, struct subtree_s *tree, struct iq_s *iq);
|
|
void *usrptr;
|
|
char to[1];
|
|
} *pendingiqs;
|
|
|
|
#ifdef JINGLE
|
|
struct c2c_s
|
|
{
|
|
struct c2c_s *next;
|
|
qboolean accepted; //connection is going
|
|
qboolean creator; //true if we're the creator.
|
|
unsigned int peercaps;
|
|
qboolean displayed; //temp flag for displaying jingle sessions with people that are not on our buddy list for whatever reasons
|
|
|
|
struct
|
|
{
|
|
char name[64]; //uniquely identifies the content within the session.
|
|
enum iceproto_e mediatype;
|
|
enum icemode_e method; //ICE_RAW or ICE_ICE. this is what the peer asked for. updated if we degrade it.
|
|
struct icestate_s *ice;
|
|
char *peeraddr;
|
|
int peerport;
|
|
} content[3];
|
|
int contents;
|
|
|
|
char *with;
|
|
char sid[1];
|
|
} *c2c;
|
|
#endif
|
|
|
|
#ifdef FILETRANSFERS
|
|
struct ft_s
|
|
{
|
|
struct ft_s *next;
|
|
char fname[MAX_QPATH];
|
|
int size;
|
|
int sizedone;
|
|
char *with;
|
|
char md5hash[16];
|
|
int privateid;
|
|
char iqid[64];
|
|
char sid[64];
|
|
int blocksize;
|
|
unsigned short seq;
|
|
qhandle_t file;
|
|
qhandle_t stream;
|
|
qboolean begun; //handshake
|
|
qboolean eof;
|
|
qboolean transmitting; //we're offering
|
|
qboolean allowed; //if false, don't handshake the transfer
|
|
|
|
struct
|
|
{
|
|
char jid[128];
|
|
char host[40];
|
|
int port;
|
|
} streamhosts[16];
|
|
int nexthost;
|
|
enum
|
|
{
|
|
STRM_IDLE,
|
|
STRM_AUTH,
|
|
STRM_AUTHED,
|
|
STRM_ACTIVE
|
|
} streamstatus;
|
|
char indata[64]; //only for handshake data
|
|
int inlen;
|
|
|
|
enum
|
|
{
|
|
FT_NOTSTARTED,
|
|
FT_IBB, //in-band bytestreams
|
|
FT_BYTESTREAM //aka: relay
|
|
} method;
|
|
} *ft;
|
|
int privateidseq;
|
|
#endif
|
|
|
|
|
|
//persistant achived info about buddies, to avoid spamming the server every time we connect
|
|
//such things might result in lag mid game!
|
|
struct buddyinfo_s
|
|
{
|
|
struct buddyinfo_s *next;
|
|
char *image;
|
|
char *imagehash;
|
|
char *imagemime;
|
|
char accountdomain[1];
|
|
} *buddyinfo;
|
|
|
|
buddy_t *buddies;
|
|
struct iq_s *avatarupdate; //we only grab one buddy's photo at a time, this is to avoid too much spam.
|
|
} jclient_t;
|
|
|
|
|
|
#ifdef JINGLE
|
|
extern icefuncs_t *piceapi;
|
|
#endif
|
|
|
|
|
|
qboolean NET_DNSLookup_SRV(const char *host, char *out, int outlen);
|
|
|
|
//xmpp functionality
|
|
struct iq_s *JCL_SendIQNode(jclient_t *jcl, qboolean (*callback) (jclient_t *jcl, xmltree_t *tree, struct iq_s *iq), const char *iqtype, const char *target, xmltree_t *node, qboolean destroynode);
|
|
void JCL_AddClientMessagef(jclient_t *jcl, const char *fmt, ...);
|
|
void JCL_AddClientMessageString(jclient_t *jcl, const char *msg);
|
|
qboolean JCL_FindBuddy(jclient_t *jcl, const char *jid, buddy_t **buddy, bresource_t **bres, qboolean create);
|
|
void JCL_ForgetBuddy(jclient_t *jcl, buddy_t *buddy, bresource_t *bres);
|
|
|
|
//quake functionality
|
|
void JCL_GenLink(jclient_t *jcl, char *out, int outlen, const char *action, const char *context, const char *contextres, const char *sid, const char *txtfmt, ...);
|
|
void Con_SubPrintf(const char *subname, const char *format, ...);
|
|
void XMPP_ConversationPrintf(const char *context, const char *title, char *format, ...);
|
|
|
|
//jingle functions
|
|
void JCL_Join(jclient_t *jcl, const char *target, const char *sid, qboolean allow, int protocol);
|
|
void JCL_JingleTimeouts(jclient_t *jcl, qboolean killall);
|
|
//jingle iq message handlers
|
|
qboolean JCL_HandleGoogleSession(jclient_t *jcl, xmltree_t *tree, const char *from, const char *id);
|
|
qboolean JCL_ParseJingle(jclient_t *jcl, xmltree_t *tree, const char *from, const char *id);
|
|
|
|
void XMPP_FT_AcceptFile(jclient_t *jcl, int fileid, qboolean accept);
|
|
qboolean XMPP_FT_OfferAcked(jclient_t *jcl, xmltree_t *x, struct iq_s *iq);
|
|
qboolean XMPP_FT_ParseIQSet(jclient_t *jcl, const char *iqfrom, const char *iqid, xmltree_t *tree);
|
|
void XMPP_FT_SendFile(jclient_t *jcl, const char *console, const char *to, const char *fname);
|
|
void XMPP_FT_Frame(jclient_t *jcl);
|
|
|
|
void Base64_Add(const char *s, int len);
|
|
char *Base64_Finish(void);
|
|
int Base64_Decode(char *out, int outlen, const char *src, int srclen);
|