jacc

Jabber/XMPP client for Plan 9
git clone git://r-36.net/jacc
Log | Files | Refs | LICENSE

recv.c (21834B)


      1 /*
      2  * Copy me if you can.
      3  * by 20h
      4  */
      5 
      6 #include <u.h>
      7 #include <libc.h>
      8 #include "xmlpull.h"
      9 #include "jacc.h"
     10 #include "dat.h"
     11 #include "roster.h"
     12 
     13 int doignore;
     14 
     15 int
     16 recvjacc(int sock, jabberc *me, char *pass)
     17 {
     18 	xmlpull *x, *b;
     19 	char *id, *to, *from, *tmstmp, st, *type, *va, *xm;
     20 	rostern *ac, *p;
     21 
     22 	type = nil;
     23 	id = nil;
     24 	from = nil;
     25 	to = nil;
     26 	xm = nil;
     27 	va = nil;
     28 	st = NONE;
     29 	ac = me->rost;
     30 
     31 	if(xmljacc(sock) < 0)
     32 		return -1;
     33 	if(loginjacc(sock, me->serv) < 0)
     34 		return -1;
     35 
     36 	x = openxmlpull(sock);
     37 	while((b = nextxmlpull(x)) != nil && st != END){
     38 		tmstmp = mktmstmp('(', ')');
     39 		if(x->na != nil)
     40 			x->na = filterzur(x->na);
     41 		if(x->va != nil)
     42 			x->va = filterzur(x->va);
     43 		switch(b->ev){
     44 		case START_DOCUMENT:
     45 			if(me->debug)
     46 				print("Start.\n");
     47 			st = NONE;
     48 			break;
     49 		case START_TAG:
     50 			if(me->debug)
     51 				print("Tag: %s\n", x->na);
     52 			if(!strcmp(x->na, "stream:stream")){
     53 				st = STREAM;
     54 				break;
     55 			}
     56 			if(!strcmp(x->na, "stream:error")){
     57 				st = ERROR;
     58 				break;
     59 			}
     60 			if(st == ERROR){
     61 				if(strcmp(x->na, "text"))
     62 					fprint(2, "%serror: %s\n", tmstmp, x->na);
     63 				break;
     64 			}
     65 			if(!strcmp(x->na, "message")){
     66 				st = MESSAGE;
     67 				break;
     68 			}
     69 			if(!strcmp(x->na, "presence")){
     70 				id = nil;
     71 				st = PRESENCE;
     72 				break;
     73 			}
     74 			if(!strcmp(x->na, "iq")){
     75 				st = IQ;
     76 				break;
     77 			}
     78 			if(!strcmp(x->na, "vCard") && st == IQ){
     79 				st = IQ_VCARD;
     80 				break;
     81 			}
     82 			if(!strcmp(x->na, "error") && st == IQ){
     83 				st = IQ_ERROR;
     84 				break;
     85 			}
     86 			if(!strcmp(x->na, "body") && st == MESSAGE){
     87 				st = MESSAGE_INNER;
     88 				break;
     89 			}
     90 			if(!strcmp(x->na, "html") && st == MESSAGE){
     91 				st = MESSAGE_HTML;
     92 				break;
     93 			}
     94 			if(!strcmp(x->na, "status") && (st == PRESENCE || st == PRESENCE_SET)){
     95 				st = PRESENCE_STATUS;
     96 				break;	
     97 			}
     98 			if(!strcmp(x->na, "show") && (st == PRESENCE || st == PRESENCE_SET)){
     99 				st = PRESENCE_SHOW;
    100 				break;
    101 			}
    102 			if(!strcmp(x->na, "error") && (st == PRESENCE || st == PRESENCE_SET)){
    103 				st = PRESENCE_ERROR;
    104 				break;
    105 			}
    106 			if(!strcmp(x->na, "x") && st == PRESENCE){
    107 				st = PRESENCE_X;
    108 				break;
    109 			}
    110 			if(!strcmp(x->na, "item") && st == ROSTER){
    111 				if(me->rost == nil){
    112 					me->rost = mkrostern();
    113 					ac = mkrostern();
    114 					me->rost->n = ac;
    115 					me->rost->p = nil;
    116 					me->rost->name = strdup(me->name);
    117 					me->rost->jid = strdup(me->jid);
    118 					me->rost->status = strdup(me->stat);
    119 					me->rost->show = strdup(me->show);
    120 					me->rost->subsc = strdup("self");
    121 					me->rost->group = strdup("self");
    122 				} else {
    123 					ac->n = mkrostern();
    124 					ac->n->p = ac;
    125 					ac = ac->n;
    126 					ac->n = nil;
    127 				}
    128 					
    129 				st = ROSTER_INNER;
    130 				break;
    131 			}
    132 			if(!strcmp(x->na, "query") && st == IQ){
    133 				st = IQ_INNER;
    134 				break;
    135 			}
    136 			if(!strcmp(x->na, "item") && st == IQ_INNER){
    137 				st = IQ_ITEM;
    138 				ac = mkrostern();
    139 				break;
    140 			}
    141 			if(!strcmp(x->na, "group") && st == IQ_ITEM){
    142 				st = IQ_GROUP;
    143 				break;
    144 			}
    145 			if(!strcmp(x->na, "group") && st == ROSTER_INNER){
    146 				st = ROSTER_GROUP;
    147 				break;
    148 			}
    149 			if(!strcmp(x->na, "utc") && st == IQ_TIME){
    150 				st = IQ_TIME_UTC;
    151 				break;
    152 			}
    153 			if(!strcmp(x->na, "tz") && st == IQ_TIME){
    154 				st = IQ_TIME_TZ;
    155 				break;
    156 			}
    157 			if(!strcmp(x->na, "display") && st == IQ_TIME){
    158 				st = IQ_TIME_DISPLAY;
    159 				break;
    160 			}
    161 			if(!strcmp(x->na, "item") && st == IQ_DISCO){
    162 				st = IQ_DISCO_ITEM;
    163 				break;
    164 			}
    165 			if(!strcmp(x->na, "identity") && st == IQ_DISCO){
    166 				print("%sserver identity:\n", tmstmp);
    167 				st = IQ_DISCO_IDENT;
    168 				break;
    169 			}
    170 			if(!strcmp(x->na, "feature") && st == IQ_DISCO){
    171 				st = IQ_DISCO_FEATU;
    172 				break;
    173 			}
    174 			if(!strcmp(x->na, "empty") && st == IQ_DISCO){
    175 				st = IQ_DISCO_EMPTY;
    176 				break;
    177 			}
    178 			if(!strcmp(x->na, "version") && st == IQ_VERSION){
    179 				st = IQ_VERSION_VER;
    180 				break;
    181 			}
    182 			if(!strcmp(x->na, "os") && st == IQ_VERSION){
    183 				st = IQ_VERSION_OS;
    184 				break;
    185 			}
    186 			if(!strcmp(x->na, "name") && st == IQ_VERSION){
    187 				st = IQ_VERSION_NAME;
    188 				break;
    189 			}
    190 			if(!strcmp(x->na, "agent") && st == IQ_AGENTS){
    191 				st = IQ_AGENTS_AGENT;
    192 				break;
    193 			}
    194 			if(!strcmp(x->na, "name") && st == IQ_AGENTS_AGENT){
    195 				st = IQ_AGENTS_NAME;
    196 				break;
    197 			}
    198 			if(!strcmp(x->na, "description") && st == IQ_AGENTS_AGENT){
    199 				st = IQ_AGENTS_DESC;
    200 				break;
    201 			}
    202 			if(!strcmp(x->na, "transport") && st == IQ_AGENTS_AGENT){
    203 				print("%s  This is a transport.\n", tmstmp);
    204 				break;
    205 			}
    206 			if(!strcmp(x->na, "groupchat") && st == IQ_AGENTS_AGENT){
    207 				print("%s  You can groupchat here.\n", tmstmp);
    208 				break;
    209 			}
    210 			if(!strcmp(x->na, "service") && st == IQ_AGENTS_AGENT){
    211 				st = IQ_AGENTS_SERV;
    212 				break;
    213 			}
    214 			if(!strcmp(x->na, "register") && st == IQ_AGENTS_AGENT){
    215 				print("%s  You can register here.\n", tmstmp);
    216 				break;
    217 			}
    218 			if(!strcmp(x->na, "search") && st == IQ_AGENTS_AGENT){
    219 				print("%s  You can search here.\n", tmstmp);
    220 				break;
    221 			}
    222 			if(st == IQ_VCARD){
    223 				if(!strcmp(x->na, "FN"))
    224 					goto is_vcard_inner;
    225 				if(!strcmp(x->na, "GIVEN"))
    226 					goto is_vcard_inner;
    227 				if(!strcmp(x->na, "FAMILY"))
    228 					goto is_vcard_inner;
    229 				if(!strcmp(x->na, "MIDDLE"))
    230 					goto is_vcard_inner;
    231 				if(!strcmp(x->na, "PREFIX"))
    232 					goto is_vcard_inner;
    233 				if(!strcmp(x->na, "SUFFIX"))
    234 					goto is_vcard_inner;
    235 				if(!strcmp(x->na, "VERSION"))
    236 					goto is_vcard_inner;
    237 				if(!strcmp(x->na, "NICKNAME"))
    238 					goto is_vcard_inner;
    239 				if(!strcmp(x->na, "PHOTO"))
    240 					goto is_vcard_inner;
    241 				if(!strcmp(x->na, "BDAY"))
    242 					goto is_vcard_inner;
    243 				if(!strcmp(x->na, "POBOX"))
    244 					goto is_vcard_inner;
    245 				if(!strcmp(x->na, "EXTADR"))
    246 					goto is_vcard_inner;
    247 				if(!strcmp(x->na, "STREET"))
    248 					goto is_vcard_inner;
    249 				if(!strcmp(x->na, "LOCALITY"))
    250 					goto is_vcard_inner;
    251 				if(!strcmp(x->na, "REGION"))
    252 					goto is_vcard_inner;
    253 				if(!strcmp(x->na, "PCODE"))
    254 					goto is_vcard_inner;
    255 				if(!strcmp(x->na, "CTRY"))
    256 					goto is_vcard_inner;
    257 				if(!strcmp(x->na, "NUMBER"))
    258 					goto is_vcard_inner;
    259 				if(!strcmp(x->na, "USERID"))
    260 					goto is_vcard_inner;
    261 				if(!strcmp(x->na, "JABBERID"))
    262 					goto is_vcard_inner;
    263 				if(!strcmp(x->na, "MAILER"))
    264 					goto is_vcard_inner;
    265 				if(!strcmp(x->na, "LAT"))
    266 					goto is_vcard_inner;
    267 				if(!strcmp(x->na, "LON"))
    268 					goto is_vcard_inner;
    269 				if(!strcmp(x->na, "TITLE"))
    270 					goto is_vcard_inner;
    271 				if(!strcmp(x->na, "ROLE"))
    272 					goto is_vcard_inner;
    273 				if(!strcmp(x->na, "AGENT"))
    274 					goto is_vcard_inner;
    275 				if(!strcmp(x->na, "ORGNAME"))
    276 					goto is_vcard_inner;
    277 				if(!strcmp(x->na, "ORGUNIT"))
    278 					goto is_vcard_inner;
    279 				if(!strcmp(x->na, "NOTE"))
    280 					goto is_vcard_inner;
    281 				if(!strcmp(x->na, "PRODID"))
    282 					goto is_vcard_inner;
    283 				if(!strcmp(x->na, "REV"))
    284 					goto is_vcard_inner;
    285 				if(!strcmp(x->na, "PHONETIC"))
    286 					goto is_vcard_inner;
    287 				if(!strcmp(x->na, "DESC"))
    288 					goto is_vcard_inner;
    289 				if(!strcmp(x->na, "CRED"))
    290 					goto is_vcard_inner;
    291 				if(!strcmp(x->na, "HOME"))
    292 					goto is_vcard_end;
    293 				if(!strcmp(x->na, "WORK"))
    294 					goto is_vcard_end;
    295 				if(!strcmp(x->na, "POSTAL"))
    296 					goto is_vcard_end;
    297 				if(!strcmp(x->na, "PARCEL"))
    298 					goto is_vcard_end;
    299 				if(!strcmp(x->na, "DOM"))
    300 					goto is_vcard_end;
    301 				if(!strcmp(x->na, "INTL"))
    302 					goto is_vcard_end;
    303 				if(!strcmp(x->na, "PREF"))
    304 					goto is_vcard_end;
    305 				if(!strcmp(x->na, "VOICE"))
    306 					goto is_vcard_end;
    307 				if(!strcmp(x->na, "FAX"))
    308 					goto is_vcard_end;
    309 				if(!strcmp(x->na, "PAGER"))
    310 					goto is_vcard_end;
    311 				if(!strcmp(x->na, "MSG"))
    312 					goto is_vcard_end;
    313 				if(!strcmp(x->na, "CELL"))
    314 					goto is_vcard_end;
    315 				if(!strcmp(x->na, "VIDEO"))
    316 					goto is_vcard_end;
    317 				if(!strcmp(x->na, "BBS"))
    318 					goto is_vcard_end;
    319 				if(!strcmp(x->na, "MODEM"))
    320 					goto is_vcard_end;
    321 				if(!strcmp(x->na, "ISDN"))
    322 					goto is_vcard_end;
    323 				if(!strcmp(x->na, "PCS"))
    324 					goto is_vcard_end;
    325 				if(!strcmp(x->na, "INTERNET"))
    326 					goto is_vcard_end;
    327 				if(!strcmp(x->na, "X400"))
    328 					goto is_vcard_end;
    329 				break;
    330 is_vcard_end:
    331 				print("%s%s\n", tmstmp, x->na);
    332 				break;
    333 is_vcard_inner:
    334 				print("%s%s = ", tmstmp, x->na);
    335 				st = IQ_VCARD_INNER;
    336 				break;
    337 			}
    338 			break;
    339 		case START_END_TAG:
    340 			if(me->debug)
    341 				print("Startend: %s\n", x->na);
    342 			if(!strcmp(x->na, "empty") && st == IQ_DISCO){
    343 				print("%s <empty>\n", tmstmp);
    344 				break;
    345 			}
    346 			if(!strcmp(x->na, "transport") && st == IQ_AGENTS_AGENT){
    347 				print("%s  This is a transport.\n", tmstmp);
    348 				break;
    349 			}
    350 			if(!strcmp(x->na, "groupchat") && st == IQ_AGENTS_AGENT){
    351 				print("%s  You can groupchat here.\n", tmstmp);
    352 				break;
    353 			}
    354 			if(!strcmp(x->na, "register") && st == IQ_AGENTS_AGENT){
    355 				print("%s  You can register here.\n", tmstmp);
    356 				break;
    357 			}
    358 			if(!strcmp(x->na, "search") && st == IQ_AGENTS_AGENT){
    359 				print("%s  You can search here.\n", tmstmp);
    360 				break;
    361 			}
    362 			if(st == ERROR || st == PRESENCE_ERROR || st == IQ_ERROR){
    363 				fprint(2, "%serror: %s\n", tmstmp, x->na);
    364 				break;
    365 			}		
    366 			break;
    367 		case TEXT:
    368 			if(me->debug)
    369 				print("Text: %s\n", x->na);
    370 			switch(st){
    371 			case MESSAGE_INNER:
    372 				type = strdup(x->na);
    373 				break;
    374 			case PRESENCE_SHOW:
    375 				if(type == nil || (type != nil && strcmp(type, "error")))
    376 					if(statusrostern(me->rost, from, from, nil, x->na) != nil)
    377 						print("%s%s> %s\n", tmstmp, namerostern(me->rost, from, nil), x->na);
    378 				break;
    379 			case PRESENCE_STATUS:
    380 				if(type == nil || (type != nil && strcmp(type, "error")))
    381 					if(statusrostern(me->rost, from, from, x->na, nil) != nil)
    382 						print("%s%s> %s\n", tmstmp, namerostern(me->rost, from, nil), x->na);
    383 				break;
    384 			case PRESENCE_ERROR:
    385 				print("%s%s# %s\n", tmstmp, namerostern(me->rost, from, nil), x->na);
    386 				free(type);
    387 				type = strdup("isdone");
    388 				break;
    389 			case ROSTER_GROUP:
    390 				if(ac->group == nil)
    391 					ac->group = strdup(x->na);
    392 				break;
    393 			case IQ_GROUP:
    394 				if(ac->group == nil)
    395 					ac->group = strdup(x->na);
    396 				break;
    397 			case IQ_ERROR:
    398 				print("%sIQ-Error: %s\n", tmstmp, x->na);
    399 				break;
    400 			case IQ_VCARD_INNER:
    401 				print("%s\n", x->na);
    402 				break;
    403 			case IQ_VERSION_OS:
    404 				print("%s  os = %s\n", tmstmp, x->na);
    405 				break;
    406 			case IQ_VERSION_NAME:
    407 				print("%s  name = %s\n", tmstmp, x->na);
    408 				break;
    409 			case IQ_VERSION_VER:
    410 				print("%s  version = %s\n", tmstmp, x->na);
    411 				break;
    412 			case IQ_TIME_UTC:
    413 				print("%sutc = %s\n", tmstmp, x->na);
    414 				break;
    415 			case IQ_TIME_TZ:
    416 				print("%stz = %s\n", tmstmp, x->na);
    417 				break;
    418 			case IQ_TIME_DISPLAY:
    419 				print("%sdisplay = %s\n", tmstmp, x->na);
    420 				break;
    421 			case IQ_AGENTS_NAME:
    422 				print("%s  name = %s\n", tmstmp, x->na);
    423 				break;
    424 			case IQ_AGENTS_DESC:
    425 				print("%s  description = %s\n", tmstmp, x->na);
    426 				break;
    427 			case IQ_AGENTS_SERV:
    428 				print("%s  service = %s\n", tmstmp, x->na);
    429 				break;
    430 			default:
    431 				break;
    432 			}
    433 			break;
    434 		case ATTR:
    435 			if(me->debug)
    436 				print("Attr: %s = %s\n", x->na, x->va);
    437 			switch(st){
    438 			case STREAM:
    439 				if(!strcmp(x->na, "id")){
    440 					st = NONE;
    441 					if(me->reg){
    442 						registerjacc(sock, me->serv, me->name, pass);
    443 						break;
    444 					}
    445 					if(userjacc(sock, me->name, pass, me->reso) < 0) {
    446 						memset(pass, 0, strlen(pass));
    447 						st = AUTH;
    448 						break;
    449 					}
    450 				}
    451 				break;
    452 			case MESSAGE:
    453 				if(!strcmp(x->na, "from"))
    454 					from = strdup(x->va);
    455 				if(!strcmp(x->na, "to"))
    456 					to = strdup(x->va);
    457 				if(!strcmp(x->na, "type"))
    458 					type = strdup(x->va);
    459 				break;
    460 			case PRESENCE:
    461 				if(!strcmp(x->na, "from"))
    462 					from = strdup(x->va);
    463 				if(!strcmp(x->na, "type"))
    464 					type = strdup(x->va);
    465 				break;
    466 			case IQ:
    467 				if(!strcmp(x->na, "id")){
    468 					if(!strcmp(x->va, "auth_1"))
    469 						rosterjacc(sock);
    470 					if(!strcmp(x->va, "auth_2"))
    471 						st = ROSTER;
    472 					if(!strcmp(x->va, "disco0"))
    473 						st = IQ_DISCO;
    474 					if(!strcmp(x->va, "time0"))
    475 						st = IQ_TIME;
    476 					if(!strcmp(x->va, "agents0"))
    477 						st = IQ_AGENTS;
    478 					if(!strcmp(x->va, "last0"))
    479 						st = IQ_LAST;
    480 					if(!strcmp(x->va, "version0"))
    481 						st = IQ_VERSION;
    482 					id = strdup(x->va);
    483 				}
    484 				if(!strcmp(x->na, "from"))
    485 					from = strdup(x->va);
    486 				if(!strcmp(x->na, "to"))
    487 					to = strdup(x->va);
    488 				if(!strcmp(x->na, "type"))
    489 					type = strdup(x->va);
    490 				break;
    491 			case ROSTER_INNER:
    492 				if(!strcmp(x->na, "name")){
    493 					ac->name = strdup(x->va);
    494 					break;
    495 				}
    496 				if(!strcmp(x->na, "jid")){
    497 					ac->jid = strdup(x->va);
    498 					break;
    499 				}
    500 				break;
    501 			case IQ_INNER:
    502 				if(!strcmp(x->na, "xmlns")){
    503 					if(xm != nil)
    504 						free(xm);
    505 					xm = strdup(x->va);
    506 				}
    507 				if(!strcmp(x->na, "name")){
    508 					if(va != nil)
    509 						free(va);
    510 					va = strdup(x->va);
    511 				}
    512 				break;
    513 			case IQ_ITEM:
    514 				if(!strcmp(x->na, "subscription")){
    515 					ac->subsc = strdup(x->va);
    516 					break;
    517 				}
    518 				if(!strcmp(x->na, "jid")){
    519 					ac->jid = strdup(x->va);
    520 					break;
    521 				}
    522 				if(!strcmp(x->na, "name")){
    523 					ac->name = strdup(x->va);
    524 					break;
    525 				}
    526 				break;
    527 			case IQ_DISCO_IDENT:
    528 				print("%s%s = %s\n", tmstmp, x->na, x->va);
    529 				break;
    530 			case IQ_DISCO_FEATU:
    531 				print("%s  %s\n", tmstmp, x->va);
    532 				break;
    533 			case IQ_DISCO_ITEM:
    534 				if(!strcmp(x->na, "name")){
    535 					if(id != nil)
    536 						free(id);
    537 					id = strdup(x->va);
    538 				}
    539 				if(!strcmp(x->na, "jid")){
    540 					if(to != nil)
    541 						free(to);
    542 					to = strdup(x->va);
    543 				}
    544 				break;
    545 			case IQ_AGENTS_AGENT:
    546 				if(!strcmp(x->na, "jid"))
    547 					print("%s%s:\n", tmstmp, x->va);
    548 				break;
    549 			case IQ_LAST:
    550 				if(!strcmp(x->na, "seconds"))
    551 					print("%s%s> %ss away\n", tmstmp, namerostern(me->rost, nil, from), x->va);
    552 				break;
    553 			default:
    554 				break;
    555 			}
    556 			break;
    557 		case END_TAG:
    558 			if(me->debug)
    559 				print("Endtag: %s\n", x->na);
    560 			if(!strcmp(x->na, "stream:stream")){
    561 				st = END;
    562 				break;
    563 			}
    564 			if(!strcmp(x->na, "stream:error") && st == ERROR){
    565 				st = NONE;
    566 				break;
    567 			}
    568 			if(st == ERROR)
    569 				break;
    570 			if(!strcmp(x->na, "message") && st == MESSAGE){
    571 				if(type != nil) {
    572 					print("%s(%s-%s)%% %s\n", tmstmp,
    573 									(from != nil) ? namerostern(me->rost, from, nil) : "<nil>",
    574 									(to != nil) ? namerostern(me->rost, to, nil) : "<nil>",
    575 									type);
    576 					playmp3("jacc_gotmessage.mp3");
    577 				}
    578 				if(from != nil)
    579 					free(from);
    580 				if(to != nil)
    581 					free(to);
    582 				if(type != nil)
    583 					free(type);
    584 				from = nil;
    585 				to = nil;
    586 				type = nil;
    587 				st = NONE;
    588 				break;
    589 			}
    590 			if(!strcmp(x->na, "presence") && st == PRESENCE_SET){
    591 				if(type != nil)
    592 					free(type);
    593 				if(from != nil)
    594 					free(from);
    595 				type = nil;
    596 				from = nil;
    597 				st = NONE;
    598 				break;
    599 			}
    600 			if(!strcmp(x->na, "presence") && st == PRESENCE){
    601 				if(type != nil && from != nil){
    602 					if(!strcmp(type, "unavailable") || !strcmp(type, "error")){
    603 						if(statusrostern(me->rost, from, from, nil, "Offline") != nil)
    604 							print("%s%s> Offline\n", tmstmp, namerostern(me->rost, from, nil));
    605 						goto presence_strcmp;
    606 					}
    607 					if(!strcmp(type, "probe")){
    608 						presencejacc(sock, me->stat, me->show, me->jid, from);
    609 						goto presence_strcmp;
    610 					}
    611 					if(!strcmp(type, "subscribe")){
    612 						statusrostern(me->rost, from, from, nil, "Online");
    613 						print("%s%s wants to subscribe\n", tmstmp, namerostern(me->rost, from, nil));
    614 						goto presence_strcmp;
    615 					}
    616 					if(!strcmp(type, "unsubscribe")){
    617 						if(statusrostern(me->rost, from, from, nil, "Offline") != nil)
    618 							print("%s%s wants to unsubscribe\n", tmstmp, namerostern(me->rost, from, nil));
    619 						goto presence_strcmp;
    620 					}
    621 					if(!strcmp(type, "subscribed")){
    622 						print("%s%s has accepted the subscription request\n", tmstmp, namerostern(me->rost, from, nil));
    623 						goto presence_strcmp;
    624 					}
    625 					if(!strcmp(type, "isdone"))
    626 						goto presence_strcmp;
    627 				}
    628 				if(from != nil) {
    629 					statusrostern(me->rost, from, from, nil, "Online");
    630 					print("%s%s> Online\n", tmstmp, namerostern(me->rost, from, nil));
    631 				}
    632 presence_strcmp:
    633 				if(type != nil)
    634 					free(type);
    635 				if(from != nil)
    636 					free(from);
    637 				type = nil;
    638 				from = nil;
    639 
    640 				st = NONE;
    641 				break;
    642 			}
    643 			if(!strcmp(x->na, "iq") && (st == IQ || st == IQ_DISCO)){
    644 				if(from != nil)
    645 					free(from);
    646 				if(to != nil)
    647 					free(to);
    648 				if(type != nil)
    649 					free(type);
    650 				if(id != nil)
    651 					free(id);
    652 				if(va != nil)
    653 					free(va);
    654 				if(xm != nil)
    655 					free(xm);
    656 				from = nil;
    657 				to = nil;
    658 				id = nil;
    659 				type = nil;
    660 				va = nil;
    661 				xm = nil;
    662 				st = NONE;
    663 				break;
    664 			}
    665 			if(!strcmp(x->na, "iq") && st == ROSTER){
    666 				if(from != nil)
    667 					free(from);
    668 				if(to != nil)
    669 					free(to);
    670 				if(type != nil)
    671 					free(type);
    672 				if(id != nil)
    673 					free(id);
    674 				from = nil;
    675 				to = nil;
    676 				id = nil;
    677 				type = nil;
    678 				presencejacc(sock, me->stat, me->show, nil, nil);
    679 				st = NONE;
    680 				break;
    681 			}
    682 			if(!strcmp(x->na, "vCard") && st == IQ_VCARD){
    683 				st = IQ;
    684 				break;
    685 			}
    686 			if(!strcmp(x->na, "error") && st == IQ_ERROR){
    687 				st = IQ;
    688 				break;
    689 			}
    690 			if(!strcmp(x->na, "body") && st == MESSAGE_INNER){
    691 				st = MESSAGE;
    692 				break;
    693 			}
    694 			if(!strcmp(x->na, "html") && st == MESSAGE_HTML){
    695 				st = MESSAGE;
    696 				break;
    697 			}
    698 			if(!strcmp(x->na, "status") && st == PRESENCE_STATUS){
    699 				st = PRESENCE_SET;
    700 				break;
    701 			}
    702 			if(!strcmp(x->na, "show") && st == PRESENCE_SHOW){
    703 				st = PRESENCE_SET;
    704 				break;
    705 			}
    706 			if(!strcmp(x->na, "x") && st == PRESENCE_X){
    707 				st = PRESENCE;
    708 				break;
    709 			}
    710 			if(!strcmp(x->na, "error") && st == PRESENCE_ERROR){
    711 				st = PRESENCE;
    712 				break;
    713 			}
    714 			if(!strcmp(x->na, "item") && st == ROSTER_INNER){
    715 				if(!doignore)
    716 					print("%sAdded user: %s/%s/%s\n", tmstmp, ac->name, ac->jid, ac->group);
    717 				st = ROSTER;
    718 				break;
    719 			}
    720 			if(!strcmp(x->na, "query") && (st == IQ_INNER || st == IQ_VERSION || st == IQ_TIME || st == IQ_LAST || st == IQ_AGENTS)){
    721 				if(st == IQ_INNER && xm != nil){
    722 					if(!strcmp(xm, "jabber:iq:version")){
    723 						if(strcmp(to, me->jid))
    724 							break;
    725 						else
    726 							versionjacc(sock, me->jid, from, id);
    727 						break;
    728 					}
    729 					if(!strcmp(xm, "jabber:iq:last"))
    730 						if(!strcmp(me->jid, to))
    731 							lastjacc(sock, to, from, id, time(0) - me->last);
    732 					if(!strcmp(xm, "http://jabber.org/protocol/disco#info"))
    733 						if(!strcmp(me->jid, to))
    734 							if(id != nil && strcmp(id, "http://jabber.org/protocol/muc#rooms"))
    735 								featuresjacc(sock, to, from, id);
    736 					if(!strcmp(xm, "jabber:iq:time"))
    737 						if(!strcmp(me->jid, to))
    738 							timejacc(sock, to, from, id);
    739 				}
    740 				st = IQ;
    741 				break;
    742 			}
    743 			if(!strcmp(x->na, "item") && st == IQ_ITEM){
    744 				st = IQ_INNER;
    745 				if(ac != nil && ac->subsc != nil){
    746 					if(!strcmp(ac->subsc, "remove")){
    747 						me->rost = delname(me->rost, ac->name, ac->jid);
    748 						print("%sremoved: %s\n", tmstmp, ac->jid);
    749 						freerostern(ac);
    750 						break;
    751 					}
    752 					if(!strcmp(ac->subsc, "both") || !strcmp(ac->subsc, "to") ||
    753 					   !strcmp(ac->subsc, "from") || !strcmp(ac->subsc, "none") ||
    754 					   !strcmp(ac->subsc, "ask")){
    755 						if(!strcmp(ac->subsc, "ask"))
    756 							print("%s%s asks for authorisation.\n", tmstmp, ac->jid);
    757 						if((p = searchrostern(me->rost, ac->name, ac->jid)) == nil){
    758 							ac->subsc = strdup(ac->subsc);
    759 							addrostern(me->rost, ac);
    760 							if(strcmp(ac->subsc, "ask"))
    761 								print("%sadded: %s\n", tmstmp, ac->jid);
    762 						} else {
    763 							if(p->jid != nil)
    764 								free(p->jid);
    765 							if(ac->jid != nil)
    766 								p->jid = strdup(ac->jid);
    767 							else
    768 								p->jid = nil;
    769 
    770 							if(p->name != nil)
    771 								free(p->name);
    772 							if(ac->name != nil)
    773 								p->name = strdup(ac->name);
    774 							else
    775 								p->name = nil;
    776 
    777 							if(p->subsc != nil)
    778 								free(p->subsc);
    779 							if(ac->subsc != nil)
    780 								p->subsc = strdup(ac->subsc);
    781 							else
    782 								p->subsc = nil;
    783 
    784 							print("%supdate: %s/%s\n", tmstmp, (ac->name == nil) ? "<nil>" : ac->name
    785 										, (ac->jid == nil) ? "<nil>" : ac->jid);
    786 							freerostern(ac);
    787 						}
    788 					}
    789 				}
    790 				ac = nil;
    791 				break;
    792 			}
    793 			if(!strcmp(x->na, "group") && st == IQ_GROUP){
    794 				st = IQ_ITEM;
    795 				break;
    796 			}
    797 			if(!strcmp(x->na, "group") && st == ROSTER_GROUP){
    798 				st = ROSTER_INNER;
    799 				break;
    800 			}
    801 			if(!strcmp(x->na, "item") && st == IQ_DISCO_ITEM){
    802 				print("%s  %s | %s\n", tmstmp, to, id);
    803 				st = IQ_DISCO;
    804 				break;
    805 			}
    806 			if(!strcmp(x->na, "identity") && st == IQ_DISCO_IDENT){
    807 				print("%sfeatures:\n", tmstmp);
    808 				st = IQ_DISCO;
    809 				break;
    810 			}
    811 			if(!strcmp(x->na, "feature") && st == IQ_DISCO_FEATU){
    812 				st = IQ_DISCO;
    813 				break;
    814 			}
    815 			if(!strcmp(x->na, "empty") && st == IQ_DISCO_EMPTY){
    816 				st = IQ_DISCO;
    817 				break;
    818 			}
    819 			if(!strcmp(x->na, "utc") && st == IQ_TIME_UTC){
    820 				st = IQ_TIME;
    821 				break;
    822 			}
    823 			if(!strcmp(x->na, "tz") && st == IQ_TIME_TZ){
    824 				st = IQ_TIME;
    825 				break;
    826 			}
    827 			if(!strcmp(x->na, "display") && st == IQ_TIME_DISPLAY){
    828 				st = IQ_TIME;
    829 				break;
    830 			}
    831 			if(!strcmp(x->na, "version") && st == IQ_VERSION_VER){
    832 				st = IQ_VERSION;
    833 				break;
    834 			}
    835 			if(!strcmp(x->na, "name") && st == IQ_VERSION_NAME){
    836 				st = IQ_VERSION;
    837 				break;
    838 			}
    839 			if(!strcmp(x->na, "os") && st == IQ_VERSION_OS){
    840 				st = IQ_VERSION;
    841 				break;
    842 			}
    843 			if(!strcmp(x->na, "agent") && st == IQ_AGENTS_AGENT){
    844 				st = IQ_AGENTS;
    845 				print("%s\n", tmstmp);
    846 				break;
    847 			}
    848 			if(!strcmp(x->na, "name") && st == IQ_AGENTS_NAME){
    849 				st = IQ_AGENTS_AGENT;
    850 				break;
    851 			}
    852 			if(!strcmp(x->na, "description") && st == IQ_AGENTS_DESC){
    853 				st = IQ_AGENTS_AGENT;
    854 				break;
    855 			}
    856 			if((!strcmp(x->na, "transport") || !strcmp(x->na, "groupchat")
    857 					|| !strcmp(x->na, "register") || !strcmp(x->na, "search")) &&
    858 					st == IQ_AGENTS_AGENT)
    859 				break;
    860 			if(!strcmp(x->na, "service") && st == IQ_AGENTS_SERV){
    861 				st = IQ_AGENTS_AGENT;
    862 				break;
    863 			}
    864 			if(st == IQ_VCARD_INNER){
    865 				st = IQ_VCARD;
    866 				break;
    867 			}
    868 			break;
    869 		case END_DOCUMENT:
    870 			if(me->debug)
    871 				print("Documentend.\n");
    872 			st = END;
    873 			break;
    874 		default:
    875 			print("Please contact the xmlpull author about this. %x\n", b->ev);
    876 			st = END;
    877 			break;
    878 		}
    879 		free(tmstmp);
    880 	}
    881 
    882 	if(id != nil)
    883 		free(id);
    884 	freexmlpull(x);
    885 
    886 	return 0;
    887 }