123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379 |
- /* iksemel (XML parser for Jabber)
- ** Copyright (C) 2000-2004 Gurer Ozen <madcat@e-kolay.net>
- ** This code is free software; you can redistribute it and/or
- ** modify it under the terms of GNU Lesser General Public License.
- */
- #include "common.h"
- #include "iksemel.h"
- #ifdef HAVE_GETOPT_LONG
- #include <getopt.h>
- #endif
- #ifdef _WIN32
- #include <winsock.h>
- #endif
- #ifdef HAVE_GETOPT_LONG
- static struct option longopts[] = {
- { "backup", required_argument, 0, 'b' },
- { "restore", required_argument, 0, 'r' },
- { "file", required_argument, 0, 'f' },
- { "timeout", required_argument, 0, 't' },
- { "secure", 0, 0, 's' },
- { "sasl", 0, 0, 'a' },
- { "log", 0, 0, 'l' },
- { "help", 0, 0, 'h' },
- { "version", 0, 0, 'V' },
- { 0, 0, 0, 0 }
- };
- #endif
- static char *shortopts = "b:r:f:t:salhV";
- static void
- print_usage (void)
- {
- puts ("Usage: iksroster [OPTIONS]\n"
- "This is a backup tool for your jabber roster.\n"
- " -b, --backup=JID Download roster from the server.\n"
- " -r, --restore=JID Upload roster to the server.\n"
- " -f, --file=FILE Load/Save roster to this file.\n"
- " -t, --timeout=SECS Set network timeout.\n"
- " -s, --secure Use encrypted connection.\n"
- " -a, --sasl Use SASL authentication.\n"
- " -l, --log Print exchanged xml data.\n"
- " -h, --help Print this text and exit.\n"
- " -V, --version Print version and exit.\n"
- #ifndef HAVE_GETOPT_LONG
- "(long options are not supported on your system)\n"
- #endif
- #ifndef HAVE_GNUTLS
- "(secure connections are not supported on your system)\n"
- #endif
- "Report bugs to <iksemel-dev@jabberstudio.org>.");
- }
- /* stuff we keep per session */
- struct session {
- iksparser *prs;
- iksid *acc;
- char *pass;
- int features;
- int authorized;
- int counter;
- int set_roster;
- int job_done;
- };
- /* precious roster we'll deal with */
- iks *my_roster;
- /* out packet filter */
- iksfilter *my_filter;
- /* connection time outs if nothing comes for this much seconds */
- int opt_timeout = 30;
- /* connection flags */
- int opt_use_tls;
- int opt_use_sasl;
- int opt_log;
- void
- j_error (char *msg)
- {
- fprintf (stderr, "iksroster: %s\n", msg);
- exit (2);
- }
- int
- on_result (struct session *sess, ikspak *pak)
- {
- iks *x;
- if (sess->set_roster == 0) {
- x = iks_make_iq (IKS_TYPE_GET, IKS_NS_ROSTER);
- iks_insert_attrib (x, "id", "roster");
- iks_send (sess->prs, x);
- iks_delete (x);
- } else {
- iks_insert_attrib (my_roster, "type", "set");
- iks_send (sess->prs, my_roster);
- }
- return IKS_FILTER_EAT;
- }
- int
- on_stream (struct session *sess, int type, iks *node)
- {
- sess->counter = opt_timeout;
- switch (type) {
- case IKS_NODE_START:
- if (opt_use_tls && !iks_is_secure (sess->prs)) {
- iks_start_tls (sess->prs);
- break;
- }
- if (!opt_use_sasl) {
- iks *x;
- x = iks_make_auth (sess->acc, sess->pass, iks_find_attrib (node, "id"));
- iks_insert_attrib (x, "id", "auth");
- iks_send (sess->prs, x);
- iks_delete (x);
- }
- break;
- case IKS_NODE_NORMAL:
- if (strcmp ("stream:features", iks_name (node)) == 0) {
- sess->features = iks_stream_features (node);
- if (opt_use_sasl) {
- if (opt_use_tls && !iks_is_secure (sess->prs)) break;
- if (sess->authorized) {
- iks *t;
- if (sess->features & IKS_STREAM_BIND) {
- t = iks_make_resource_bind (sess->acc);
- iks_send (sess->prs, t);
- iks_delete (t);
- }
- if (sess->features & IKS_STREAM_SESSION) {
- t = iks_make_session ();
- iks_insert_attrib (t, "id", "auth");
- iks_send (sess->prs, t);
- iks_delete (t);
- }
- } else {
- if (sess->features & IKS_STREAM_SASL_MD5)
- iks_start_sasl (sess->prs, IKS_SASL_DIGEST_MD5, sess->acc->user, sess->pass);
- else if (sess->features & IKS_STREAM_SASL_PLAIN)
- iks_start_sasl (sess->prs, IKS_SASL_PLAIN, sess->acc->user, sess->pass);
- }
- }
- } else if (strcmp ("failure", iks_name (node)) == 0) {
- j_error ("sasl authentication failed");
- } else if (strcmp ("success", iks_name (node)) == 0) {
- sess->authorized = 1;
- iks_send_header (sess->prs, sess->acc->server);
- } else {
- ikspak *pak;
- pak = iks_packet (node);
- iks_filter_packet (my_filter, pak);
- if (sess->job_done == 1) return IKS_HOOK;
- }
- break;
- case IKS_NODE_STOP:
- j_error ("server disconnected");
- case IKS_NODE_ERROR:
- j_error ("stream error");
- }
- if (node) iks_delete (node);
- return IKS_OK;
- }
- int
- on_error (void *user_data, ikspak *pak)
- {
- j_error ("authorization failed");
- return IKS_FILTER_EAT;
- }
- int
- on_roster (struct session *sess, ikspak *pak)
- {
- my_roster = pak->x;
- sess->job_done = 1;
- return IKS_FILTER_EAT;
- }
- void
- on_log (struct session *sess, const char *data, size_t size, int is_incoming)
- {
- if (iks_is_secure (sess->prs)) fprintf (stderr, "Sec");
- if (is_incoming) fprintf (stderr, "RECV"); else fprintf (stderr, "SEND");
- fprintf (stderr, "[%s]\n", data);
- }
- void
- j_setup_filter (struct session *sess)
- {
- if (my_filter) iks_filter_delete (my_filter);
- my_filter = iks_filter_new ();
- iks_filter_add_rule (my_filter, (iksFilterHook *) on_result, sess,
- IKS_RULE_TYPE, IKS_PAK_IQ,
- IKS_RULE_SUBTYPE, IKS_TYPE_RESULT,
- IKS_RULE_ID, "auth",
- IKS_RULE_DONE);
- iks_filter_add_rule (my_filter, on_error, sess,
- IKS_RULE_TYPE, IKS_PAK_IQ,
- IKS_RULE_SUBTYPE, IKS_TYPE_ERROR,
- IKS_RULE_ID, "auth",
- IKS_RULE_DONE);
- iks_filter_add_rule (my_filter, (iksFilterHook *) on_roster, sess,
- IKS_RULE_TYPE, IKS_PAK_IQ,
- IKS_RULE_SUBTYPE, IKS_TYPE_RESULT,
- IKS_RULE_ID, "roster",
- IKS_RULE_DONE);
- }
- void
- j_connect (char *jabber_id, char *pass, int set_roster)
- {
- struct session sess;
- int e;
- memset (&sess, 0, sizeof (sess));
- sess.prs = iks_stream_new (IKS_NS_CLIENT, &sess, (iksStreamHook *) on_stream);
- if (opt_log) iks_set_log_hook (sess.prs, (iksLogHook *) on_log);
- sess.acc = iks_id_new (iks_parser_stack (sess.prs), jabber_id);
- if (NULL == sess.acc->resource) {
- /* user gave no resource name, use the default */
- char *tmp;
- tmp = iks_malloc (strlen (sess.acc->user) + strlen (sess.acc->server) + 9 + 3);
- sprintf (tmp, "%s@%s/%s", sess.acc->user, sess.acc->server, "iksroster");
- sess.acc = iks_id_new (iks_parser_stack (sess.prs), tmp);
- iks_free (tmp);
- }
- sess.pass = pass;
- sess.set_roster = set_roster;
- j_setup_filter (&sess);
- e = iks_connect_tcp (sess.prs, sess.acc->server, IKS_JABBER_PORT);
- switch (e) {
- case IKS_OK:
- break;
- case IKS_NET_NODNS:
- j_error ("hostname lookup failed");
- case IKS_NET_NOCONN:
- j_error ("connection failed");
- default:
- j_error ("io error");
- }
- sess.counter = opt_timeout;
- while (1) {
- e = iks_recv (sess.prs, 1);
- if (IKS_HOOK == e) break;
- if (IKS_NET_TLSFAIL == e) j_error ("tls handshake failed");
- if (IKS_OK != e) j_error ("io error");
- sess.counter--;
- if (sess.counter == 0) j_error ("network timeout");
- }
- iks_parser_delete (sess.prs);
- }
- int
- main (int argc, char *argv[])
- {
- char *from = NULL;
- char *to = NULL;
- char *file = NULL;
- char from_pw[128], to_pw[128];
- int c;
- #ifdef HAVE_GETOPT_LONG
- int i;
- while ((c = getopt_long (argc, argv, shortopts, longopts, &i)) != -1) {
- #else
- while ((c = getopt (argc, argv, shortopts)) != -1) {
- #endif
- switch (c) {
- case 'b':
- from = optarg;
- printf ("Password for %s: ", optarg);
- fflush (stdout);
- fgets (from_pw, 127, stdin);
- strtok (from_pw, "\r\n");
- break;
- case 'r':
- to = optarg;
- printf ("Password for %s: ", optarg);
- fflush (stdout);
- fgets (to_pw, 127, stdin);
- strtok (to_pw, "\r\n");
- break;
- case 'f':
- file = strdup (optarg);
- break;
- case 't':
- opt_timeout = atoi (optarg);
- if (opt_timeout < 10) opt_timeout = 10;
- break;
- case 's':
- if (!iks_has_tls ()) {
- puts ("Cannot make encrypted connections.");
- puts ("iksemel library is not compiled with GnuTLS support.");
- exit (1);
- }
- opt_use_tls = 1;
- break;
- case 'a':
- opt_use_sasl = 1;
- break;
- case 'l':
- opt_log = 1;
- break;
- case 'h':
- print_usage ();
- exit (0);
- case 'V':
- puts ("iksroster (iksemel) "VERSION);
- exit (0);
- }
- }
- if (from == NULL && to == NULL) {
- puts ("What I'm supposed to do?");
- print_usage ();
- exit (1);
- }
- if (to && (from == NULL && file == NULL)) {
- puts ("Store which roster?");
- print_usage ();
- exit (1);
- }
- #ifdef _WIN32
- WSADATA wsaData;
- WSAStartup (MAKEWORD (1,1), &wsaData);
- #endif
- if (from) {
- j_connect (from, from_pw, 0);
- if (file) {
- switch (iks_save (file, my_roster)) {
- case IKS_OK:
- break;
- case IKS_FILE_NOACCESS:
- j_error ("cannot write to file");
- default:
- j_error ("file io error");
- }
- }
- } else {
- switch (iks_load (file, &my_roster)) {
- case IKS_OK:
- break;
- case IKS_FILE_NOFILE:
- j_error ("file not found");
- case IKS_FILE_NOACCESS:
- j_error ("cannot read file");
- default:
- j_error ("file io error");
- }
- }
- if (to) {
- j_connect (to, to_pw, 1);
- }
- #ifdef _WIN32
- WSACleanup ();
- #endif
- return 0;
- }
|