jacc.c (14431B)
1 /* 2 * Copy me if you can. 3 * by 20h 4 */ 5 6 #include <u.h> 7 #include <libc.h> 8 #include <auth.h> 9 #include <mp.h> 10 #include <libsec.h> 11 #include "xmlpull.h" 12 #include "jacc.h" 13 #include "dat.h" 14 #include "roster.h" 15 #include "recv.h" 16 17 #define NAME "jacc - Jabber Client for Plan9" 18 #define VERSION "2nd ed" 19 #define OS "Plan 9 4th ed" 20 21 extern int doignore; 22 23 int 24 xmljacc(int sock) 25 { 26 return fprint(sock, "<?xml version=\"1.0\"?>\n"); 27 } 28 29 int 30 loginjacc(int sock, char *serv) 31 { 32 return fprint(sock, "<stream:stream xmlns:stream=\"http://etherx.jabber.org/streams\"" 33 " xmlns=\"jabber:client\" to=\"%s\">\n", serv); 34 } 35 36 int 37 userjacc(int sock, char *user, char *pass, char *res) 38 { 39 return fprint(sock, "<iq type=\"set\" id=\"auth_1\">\n" 40 "<query xmlns=\"jabber:iq:auth\">\n" 41 "<username>%s</username>\n" 42 "<password>%s</password>\n" 43 "<resource>%s</resource>\n" 44 "</query>\n" 45 "</iq>\n", user, pass, res); 46 } 47 48 int 49 versionjacc(int sock, char *from, char *to, char *id) 50 { 51 return fprint(sock, "<iq from=\"%s\" type=\"result\" id=\"%s\" to=\"%s\">\n" 52 "<query xmlns=\"jabber:iq:version\">\n" 53 "<name>" NAME "</name>\n" 54 "<version>" VERSION "</version>\n" 55 "<os>" OS "</os>\n" 56 "</query>\n" 57 "</iq>\n", from, (id == nil) ? "" : id, to); 58 } 59 60 int 61 featuresjacc(int sock, char *from, char *to, char *id) 62 { 63 return fprint(sock, "<iq from=\"%s\" type=\"result\" to=\"%s\" id=\"%s\">\n" 64 "<query xmlns=\"http://jabber.org/protocol/disco#info\">\n" 65 "<identity category=\"client\" type=\"pc\"/>\n" 66 "<feature var=\"jabber:iq:time\"/>\n" 67 "<feature var=\"jabber:iq:version\"/>\n" 68 "<feature var=\"http://jabber.org/protocol/muc\"/>\n" 69 "</query>\n" 70 "</iq>\n", from, to, (id == nil) ? "" : id); 71 } 72 73 int 74 timejacc(int sock, char *from, char *to, char *id) 75 { 76 Tm *lo, *gm; 77 78 lo = localtime(time(0)); 79 gm = gmtime(time(0)); 80 81 return fprint(sock, "<iq from=\"%s\" type=\"result\" to=\"%s\" id=\"%s\">\n" 82 "<query xmlns=\"jabber:iq:time\">\n" 83 "<utc>%.4d%.2d%.2dT%.2d:%.2d:%.2d</utc>\n" 84 "<display>%s %s %.2d %.2d:%.2d:%.2d %.4d</display>\n" 85 "<tz>%s</tz>\n" 86 "</query>\n" 87 "</iq>\n", from, to, (id == nil) ? "" : id, gm->year + 1900, 88 gm->mon + 1, gm->mday, gm->hour, gm->min, 89 gm->sec, getday(lo->wday), getmonth(lo->mon), 90 lo->mday, lo->hour, lo->min, lo->sec, 91 lo->year + 1900, lo->zone); 92 } 93 94 int 95 lastjacc(int sock, char *from, char *to, char *id, int d) 96 { 97 return fprint(sock, "<iq from=\"%s\" type=\"result\" to=\"%s\" id=\"%s\">\n" 98 "<query xmlns=\"jabber:iq:last\" seconds=\"%d\"/>\n" 99 "</iq>\n", from, to, (id == nil) ? "" : id, d); 100 } 101 102 int 103 registerjacc(int sock, char *serv, char *user, char *pass) 104 { 105 return fprint(sock, "<iq type=\"set\" id=\"req\" to=\"%s\">\n" 106 "<query xmlns=\"jabber:iq:register\">\n" 107 "<username>%s</username>\n" 108 "<password>%s</password>\n" 109 "</query>\n" 110 "</iq>\n", serv, user, pass); 111 } 112 113 int 114 vcardgetjacc(int sock, char *from, char *type) 115 { 116 return fprint(sock, "<iq %s=\"%s\" type=\"get\" id=\"v1\">\n" 117 "<vCard xmlns=\"vcard-temp\"/>\n" 118 "</iq>\n", type, from); 119 } 120 121 int 122 vcardsetjacc(int sock, char *from, int fd) 123 { 124 fprint(sock, "<iq from=\"%s\" type=\"set\" id=\"v2\">\n" 125 "<vCard xmlns=\"vcard-temp\">\n", from); 126 readwrite(sock, fd); 127 128 return fprint(sock, "</vCard>\n" 129 "</iq>\n"); 130 } 131 132 int 133 presencejacc(int sock, char *stat, char *show, char *from, char *to) 134 { 135 return fprint(sock, "<presence%s%s%s%s%s%s>\n" 136 "<show>%s</show>\n" 137 "<status>%s</status>\n" 138 "<priority>9</priority>\n" 139 "</presence>\n", (from != nil) ? " from=\"" : "", 140 (from != nil) ? from : "", 141 (from != nil) ? "\"" : "", 142 (to != nil) ? " to=\"" : "", 143 (to != nil) ? to : "", 144 (to != nil) ? "\"" : "", 145 (show != nil) ? show : "", 146 (stat != nil) ? stat : ""); 147 } 148 149 int 150 presencetypejacc(int sock, char *from, char *to, char *type) 151 { 152 return fprint(sock, "<presence type=\"%s\" from=\"%s\" to=\"%s\"/>\n", 153 type, from, to); 154 } 155 156 int 157 rosterjacc(int sock) 158 { 159 return fprint(sock, "<iq type=\"get\" id=\"auth_2\">\n" 160 "<query xmlns=\"jabber:iq:roster\"/>\n" 161 "</iq>\n"); 162 } 163 164 int 165 messagejacc(int sock, char *from, char *to, char *msg, char *type) 166 { 167 return fprint(sock, "<message from=\"%s\" to=\"%s\" type=\"%s\">\n" 168 "<body>%s</body>\n" 169 "</message>\n", from, to, type, msg); 170 } 171 172 int 173 addbuddyjacc(int sock, char *jid, char *na, char *group) 174 { 175 if(na == nil){ 176 na = jid; 177 jid = strchr(na, '@'); 178 179 if(jid == nil) 180 return -1; 181 *jid++ = '\0'; 182 183 return fprint(sock, "<iq type=\"set\">\n" 184 "<query xmlns=\"jabber:iq:roster\">\n" 185 "<item jid=\"%s@%s\" name=\"%s\"/>\n" 186 "%s%s%s" 187 "</query>\n" 188 "</iq>\n", na, jid, na, 189 (group != nil) ? "<group>" : "", 190 (group != nil) ? group : "", 191 (group != nil) ? "</group>\n" : ""); 192 } 193 194 return fprint(sock, "<iq type=\"set\">\n" 195 "<query xmlns=\"jabber:iq:roster\">\n" 196 "<item jid=\"%s\" name=\"%s\"/>\n" 197 "%s%s%s" 198 "</query>\n" 199 "</iq>\n", jid, na, 200 (group != nil) ? "<group>" : "", 201 (group != nil) ? group : "", 202 (group != nil) ? "</group>\n" : ""); 203 } 204 205 int 206 delbuddyjacc(int sock, char *jid) 207 { 208 return fprint(sock, "<iq type=\"set\">\n" 209 "<query xmlns=\"jabber:iq:roster\">\n" 210 "<item jid=\"%s\" subscription=\"remove\"/>\n" 211 "</query>\n" 212 "</iq>\n", jid); 213 } 214 215 int 216 xmlnsjacc(int sock, char *who, char *t, char *id) 217 { 218 return fprint(sock, "<iq type=\"get\" to=\"%s\" id=\"%s\">\n" 219 "<query xmlns=\"%s\"/>\n" 220 "</iq>\n", who, id, t); 221 } 222 223 void 224 printrostern(rostern *r, char *w) 225 { 226 char *tmstmp; 227 228 tmstmp = mktmstmp('(', ')'); 229 while(r != nil){ 230 if(w != nil){ 231 if(r->status != nil) 232 if(!strcmp(r->status, w)) 233 goto got_one; 234 if(r->name != nil) 235 if(!strcmp(r->name, w)) 236 goto got_one; 237 if(r->jid != nil) 238 if(!strcmp(r->jid, w)) 239 goto got_one; 240 if(r->show != nil) 241 if(!strcmp(r->show, w)) 242 goto got_one; 243 if(r->group != nil) 244 if(!strcmp(r->group, w)) 245 goto got_one; 246 } else { 247 got_one: 248 print("%s%s/%s on %s -> %s/%s\n", tmstmp, r->name, r->jid, r->group, r->show, r->status); 249 } 250 251 r = r->n; 252 } 253 254 return; 255 } 256 257 void 258 usage(void) 259 { 260 print("usage: [-dgit] [-r res] [-s tosrv] [net!]server[!port]\n"); 261 exits(0); 262 } 263 264 int 265 main(int argc, char *argv[]) 266 { 267 char *server, *user, *lbl, *b, *tmstmp, *buf, *toserver; 268 int sock, ts, reg, debug, tls; 269 UserPasswd *i; 270 TLSconn conn; 271 jabberc *me; 272 273 tls = 0; 274 b = nil; 275 reg = 0; 276 debug = 0; 277 toserver = nil; 278 279 ARGBEGIN { 280 case 't': 281 tls = 1; 282 break; 283 case 'r': 284 b = EARGF(usage()); 285 break; 286 case 'g': 287 reg = 1; 288 break; 289 case 'd': 290 debug = 1; 291 break; 292 case 'i': 293 doignore = 1; 294 break; 295 case 's': 296 toserver = EARGF(usage()); 297 break; 298 default: 299 usage(); 300 } ARGEND; 301 302 if(argc < 1) 303 usage(); 304 server = strdup(argv[0]); 305 306 lbl = getwindowlbl(); 307 user = reallocj(nil, strlen(server) + 9, 2); 308 snprint(user, strlen(server) + 8, "jacc - %s", server); 309 setwindowlbl(user); 310 free(user); 311 312 i = auth_getuserpasswd(auth_getkey, "proto=pass server=%s service=jabber", server); 313 if(i == nil) 314 sysfatal("auth_getuserpasswd: %r"); 315 316 sock = dial(netmkaddr(server, "tcp", tls ? "5223" : "5222"), 0, 0, 0); 317 if(sock < 0) 318 sysfatal("dial: %r"); 319 320 if(tls){ 321 ts = tlsClient(sock, &conn); 322 if(ts < 0) 323 sysfatal("tlsClient: %r"); 324 sock = ts; 325 326 if(conn.cert != nil) 327 free(conn.cert); 328 } 329 330 buf = strchr(server, '!'); 331 if(buf != nil) { 332 *buf++ = '\0'; 333 user = strchr(buf, '!'); 334 if(user != nil) 335 *user = '\0'; 336 user = strdup(buf); 337 free(server); 338 server = user; 339 } 340 341 if(toserver == nil) 342 toserver = server; 343 344 me = mkjabberc(); 345 me->show = strdup("Online"); 346 me->stat = strdup("Online"); 347 me->name = strdup(i->user); 348 me->serv = strdup(toserver); 349 350 if(b != nil) 351 me->reso = strdup(b); 352 else 353 me->reso = strdup("Plan9"); 354 me->jid = printjid(me->name, me->serv, me->reso); 355 me->debug = debug; 356 me->reg = reg; 357 me->last = time(0); 358 359 free(server); 360 361 ts = getpid(); 362 363 #ifdef PLAN9PORT 364 switch(fork()) { 365 #endif 366 #ifndef PLAN9PORT 367 switch(rfork(RFPROC|RFFDG|RFMEM)) { 368 #endif 369 case -1: 370 sysfatal("fork: %r"); 371 case 0: 372 if(recvjacc(sock, me, i->passwd) < 0) 373 perror("recvjacc"); 374 375 if(lbl != nil){ 376 setwindowlbl(lbl); 377 lbl = nil; 378 free(lbl); 379 } 380 killproc(ts); 381 exits(0); 382 default: 383 user = reallocj(nil, 1025, 2); 384 buf = nil; 385 while(sock > 0 && user != nil){ 386 ts = -1; 387 memset(user, 0, 1025); 388 389 while(read(0, &user[++ts], 1) && ts < 1024 && sock > 0) 390 if(user[ts] == '\n') 391 break; 392 user[ts] = '\0'; 393 me->last = time(0); 394 395 tmstmp = mktmstmp('(', ')'); 396 if(user[0] != '/'){ 397 if(buf != nil){ 398 b = filterhin(user, 0); 399 messagejacc(sock, me->jid, buf, b, "chat"); 400 print("%s\n", tmstmp); 401 free(b); 402 } 403 free(tmstmp); 404 continue; 405 } 406 407 switch(user[1]){ 408 case 'h': 409 case 'H': 410 print("%sHelp for jacc:\n", tmstmp); 411 print("%s /a [+|-|*]jid - authenticate jid\n", tmstmp); 412 print("%s /b - turn debugging on or off\n", tmstmp); 413 print("%s /c file - set vcard on server\n", tmstmp); 414 print("%s /d jid [feat] - do a discovery request\n", tmstmp); 415 print("%s /e jid - get time from jid\n", tmstmp); 416 print("%s /g jid - get agents information from jid\n", tmstmp); 417 print("%s /h - print out this help\n", tmstmp); 418 print("%s /i jid - get version of jid\n", tmstmp); 419 print("%s /l [status|jid|user] - list the roster\n", tmstmp); 420 print("%s /m jid - send a message to jid\n", tmstmp); 421 print("%s /p [show] [status] - set status and show\n", tmstmp); 422 print("%s /q - quit jacc\n", tmstmp); 423 print("%s /s [jid] - set active jid\n", tmstmp); 424 print("%s /t jid - get idle time of jid\n",tmstmp); 425 print("%s /u [+|-]jid [alias] - manage roster\n", tmstmp); 426 print("%s /v [jid] - get vcard from jid\n", tmstmp); 427 print("%s\n", tmstmp); 428 break; 429 case 'q': 430 case 'Q': 431 fprint(sock, "<presence from=\"%s\" type=\"unavailable\"/>", 432 me->jid); 433 fprint(sock, "</stream:stream>"); 434 free(user); 435 user = nil; 436 break; 437 case 's': 438 case 'S': 439 server = getarg(user, 1, 0); 440 if(server == nil){ 441 print("%s%s\n", tmstmp, (buf != nil) ? buf : "<nil>"); 442 break; 443 } 444 445 buf = setchan(buf, namerostern(me->rost, nil, server)); 446 free(server); 447 break; 448 case 'l': 449 case 'L': 450 server = getarg(user, 1, 0); 451 452 printrostern(me->rost, server); 453 454 if(server != nil) 455 free(server); 456 break; 457 case 'm': 458 case 'M': 459 server = getarg(user, 1, 0); 460 if(server == nil) 461 break; 462 463 b = getarg(user, 2, 2); 464 if(b == nil){ 465 free(server); 466 break; 467 } 468 469 messagejacc(sock, me->jid, namerostern(me->rost, nil, server), b, "normal"); 470 free(server); 471 free(b); 472 break; 473 case 'p': 474 case 'P': 475 server = getarg(user, 1, 0); 476 if(server == nil){ 477 print("%s%s\n", tmstmp, me->stat); 478 break; 479 } 480 481 b = getarg(user, 2, 2); 482 if(b != nil){ 483 presencejacc(sock, b, server, nil, nil); 484 free(me->stat); 485 me->stat = strdup(b); 486 } else 487 presencejacc(sock, nil, server, nil, nil); 488 free(me->show); 489 me->show = strdup(server); 490 statusrostern(me->rost, me->jid, me->jid, server, b); 491 free(server); 492 break; 493 case 'c': 494 case 'C': 495 server = getarg(user, 1, 0); 496 if(server != nil){ 497 ts = open(server, OREAD); 498 if(ts >= 0){ 499 vcardsetjacc(sock, me->jid, ts); 500 close(ts); 501 } 502 free(server); 503 } 504 break; 505 case 'v': 506 case 'V': 507 server = getarg(user, 1, 0); 508 if(server == nil){ 509 vcardgetjacc(sock, me->jid, "from"); 510 break; 511 } 512 513 vcardgetjacc(sock, namerostern(me->rost, nil, server), "to"); 514 print("Vcard of: %s\n", namerostern(me->rost, nil, server)); 515 free(server); 516 break; 517 case 'u': 518 case 'U': 519 server = getarg(user, 1, 0); 520 if(server != nil){ 521 if(server[0] == '-') 522 delbuddyjacc(sock, namerostern(me->rost, server + 1, server + 1)); 523 else { 524 b = getarg(user, 2, 0); 525 if(server[0] == '+') 526 addbuddyjacc(sock, server + 1, b, nil); 527 else 528 addbuddyjacc(sock, server, b, nil); 529 } 530 free(server); 531 } 532 break; 533 case 'a': 534 case 'A': 535 server = getarg(user, 1, 0); 536 if(server != nil){ 537 switch(server[0]){ 538 case '+': 539 presencetypejacc(sock, me->jid, namerostern(me->rost, nil, server + 1), "subscribed"); 540 break; 541 case '-': 542 presencetypejacc(sock, me->jid, namerostern(me->rost, nil, server + 1), "unsubscribe"); 543 break; 544 case '*': 545 presencetypejacc(sock, me->jid, namerostern(me->rost, nil, server + 1), "subscribe"); 546 break; 547 default: 548 presencetypejacc(sock, me->jid, namerostern(me->rost, nil, server), "subscribed"); 549 break; 550 } 551 free(server); 552 } 553 break; 554 case 'd': 555 case 'D': 556 server = getarg(user, 1, 0); 557 if(server != nil){ 558 b = getarg(user, 2, 2); 559 if(b == nil) 560 b = strdup("info"); 561 562 free(tmstmp); 563 tmstmp = reallocj(nil, 35 + strlen(b), 2); 564 sprint(tmstmp, "http://jabber.org/protocol/disco#%s", b); 565 566 xmlnsjacc(sock, server, tmstmp, "disco0"); 567 free(b); 568 free(server); 569 } 570 break; 571 case 'b': 572 case 'B': 573 if(me->debug == 0) 574 me->debug = 1; 575 else 576 me->debug = 0; 577 print("%sDebug: %c\n", tmstmp, me->debug); 578 break; 579 case 't': 580 case 'T': 581 server = getarg(user, 1, 0); 582 if(server != nil){ 583 xmlnsjacc(sock, namerostern(me->rost, nil, server), "jabber:iq:last", "last0"); 584 free(server); 585 } 586 break; 587 case 'i': 588 case 'I': 589 server = getarg(user, 1, 0); 590 if(server != nil){ 591 xmlnsjacc(sock, namerostern(me->rost, nil, server), "jabber:iq:version", "version0"); 592 free(server); 593 } 594 break; 595 case 'e': 596 case 'E': 597 server = getarg(user, 1, 0); 598 if(server != nil){ 599 xmlnsjacc(sock, namerostern(me->rost, nil, server), "jabber:iq:time", "time0"); 600 free(server); 601 } 602 break; 603 case 'g': 604 case 'G': 605 server = getarg(user, 1, 0); 606 if(server != nil){ 607 xmlnsjacc(sock, namerostern(me->rost, nil, server), "jabber:iq:agents", "agents0"); 608 free(server); 609 } 610 break; 611 default: 612 break; 613 } 614 free(tmstmp); 615 } 616 617 wait(); 618 if(lbl != nil){ 619 setwindowlbl(lbl); 620 lbl = nil; 621 free(lbl); 622 } 623 break; 624 } 625 626 freejabberc(me); 627 exits(0); 628 return 0; 629 }