summary refs log tree commit diff stats
path: root/data/icons/tray_fileoffer.png
blob: f1afc0294ae8e56a0103ff1eb16ccd5c1b28d7bc (plain)
ofshex dumpascii
0000 89 50 4e 47 0d 0a 1a 0a 00 00 00 0d 49 48 44 52 00 00 00 30 00 00 00 30 08 06 00 00 00 57 02 f9 .PNG........IHDR...0...0.....W..
0020 87 00 00 00 06 62 4b 47 44 00 ff 00 ff 00 ff a0 bd a7 93 00 00 00 09 70 48 59 73 00 00 0d d7 00 .....bKGD..............pHYs.....
0040 00 0d d7 01 42 28 9b 78 00 00 00 07 74 49 4d 45 07 dc 07 11 12 17 19 8d e7 c1 56 00 00 13 62 49 ....B(.x....tIME..........V...bI
0060 44 41 54 68 de ad 9a 77 7c 5d c5 95 c7 bf 33 f7 de d7 a4 a7 66 15 cb 72 ef 05 17 8c 6d 6a 30 cd DATh...w|]....3.....f..r....mj0.
0080 34 53 4c a8 06 42 12 58 02 61 09 84 9a a5 e3 98 92 e5 63 20 c0 52 37 1b c2 62 07 02 38 c4 60 20 4SL..B.X.a........c..R7..b..8.`.
00a0 5e 4c 31 60 16 83 8d 8d 7b c7 96 64 49 b6 ac a7 f7 9e 5e bd 65 66 ff 78 57 96 64 9b b6 c9 fd 7c ^L1`....{..dI.....^.ef.xW.d....|
00c0 e6 33 f7 95 7b ee f9 cd 39 33 67 ce ef 8c e0 1f bb c4 77 7c fe a1 97 de af ff c1 0a 7c df 4b fa .3..{...93g.......w|........|.K.
00e0 cf ca 6e f7 1c a4 ff b6 77 e8 6f 50 5c ed d7 fe a9 00 04 60 00 26 60 f9 bd b1 1f 90 ee 20 0e 06 ..n.....w.oP\......`.&`.........
0100 48 7f 03 00 0d 78 7e 73 00 db ef d5 b7 59 44 fc 40 e5 83 c0 51 7e eb 0f 54 01 95 3e 88 52 ff 3f H....x~s.....YD.@...Q~..T..>.R.?
0120 51 1f 4c f1 41 64 d8 40 ae db e7 1c 10 07 12 40 03 f0 11 b0 d4 ff 3e e3 37 1b 70 7f 30 00 7d 09 Q.L.Ad.@.......@......>.7.p.0.}.
0140 82 62 0c 86 63 6e 6a 42 be f4 25 c5 b3 3f 64 9e d6 9c 64 1a 60 19 d0 ab 0c 6a 2a 41 08 28 89 82 .b..cnjB..%..?d...d.`....j*A.(..
0160 61 40 69 31 04 2c 28 8a 1c 28 33 9e 04 ad 0b 2f 75 5c 48 26 21 9d 82 44 1c 52 19 48 e5 41 c3 7f a@i1.,(..(3..../u\H&!..D.R.H.A..
0180 1e 5a cb dc da 12 d2 89 0c 7b 23 06 f1 f2 30 99 e7 56 e2 7c 6f 00 7a 06 22 33 15 23 94 20 20 c3 .Z.......{#...0..V.|o.z."3.#....
01a0 38 cb 76 12 3e e6 19 9e 0c 85 b8 f4 be eb e1 94 a3 60 70 df 82 a2 da 97 22 7c 3b 8b ef b0 a9 d6 8.v.>............`p....."|;.....
01c0 20 7c 4f d7 2e 68 bb 70 bf f4 2b c9 3d ff 61 b0 7c ab a3 83 06 bf 3b 6e 10 9f 54 47 69 cf e5 69 .|O..h.p..+.=.a.|.....;n..TGi..i
01e0 c2 21 d6 af 96 ec ac 77 0f b4 84 b1 ff 17 ea 62 84 38 1e 43 b7 12 f0 24 5e 53 9c 92 71 8f 73 9e .!.....w.......b.8.C...$^S..q.s.
0200 65 71 c7 3b cf c0 79 27 42 38 28 08 9a be d3 fb 1e 2a 54 d7 fd 01 d3 b0 b3 75 7a b8 eb 7b b7 03 eq.;..y'B8(......*T......uz..{..
0220 d2 80 1c 82 8a 2a c1 b0 61 92 77 96 1a a2 2d a9 26 ef ea 60 99 14 24 42 26 4a 1a 38 66 1e ef 86 .....*..a.w...-.&..`..$B&J.8f...
0240 28 ea d5 b6 9e f3 41 1e 60 92 28 46 7e 2f 01 11 44 a7 f3 84 2f 79 8d 6a ad 99 f3 c4 ad 70 cc 98 (.....A.`.(F~/..D.../y.j.....p..
0260 c2 cb c3 52 e3 e4 40 d9 5d ca 68 db 1f cd ce de 39 48 73 41 78 40 0a e8 00 e1 40 26 0f 28 8d 97 ...R..@.].h.....9HsAx@....@&.(..
0280 57 4c 1e e1 70 e7 95 1e 96 25 43 b6 cb cd 55 82 be c4 a8 8e e4 29 b7 03 46 a4 a1 2f 81 fd f5 35 WL..p....%C...U......)..F../...5
02a0 0f b0 f1 50 cc 60 9a 80 0b d9 dd 39 8c e5 8d 3c 74 ee 09 94 5c 31 1d b4 03 b2 13 b2 82 d5 1b 05 ...P.`.....9...<t...\1..........
02c0 eb 37 4b 0c e5 d1 92 80 bc 07 c9 34 64 1d 48 65 7b 8a ad eb d3 9b 43 27 cf 60 c0 90 c9 54 54 d6 .7K........4d.He{.....C'.`...TT.
02e0 51 52 52 8d 30 82 24 b2 06 4e 3e 4e f9 90 28 91 22 cd 85 c3 24 d3 7e 6a 20 d1 83 a3 21 e3 d9 50 QRR.0.$..N>N..(."...$.~j....!..P
0300 28 b8 77 dd 92 bf 3c f7 c4 6d b7 cc ad 18 88 07 e4 bb 2f af 07 00 d0 69 42 3a 80 6a 4e 22 0f 7f (.w...<..m......../....iB:.jN"..
0320 8a d3 8a 8a 98 fe c4 75 e0 e6 c1 32 41 fb 8f 6e da 09 e7 de 59 84 e3 95 71 44 e5 5e 5c 3b c7 ce .......u...2A..n....Y...qD.^\;..
0340 38 ec ee 80 64 1e 32 0e 18 a6 c9 b0 a1 43 99 fd db d9 1c 7f fc f1 e4 f2 59 6c 37 8f d6 1e 71 47 8...d.2......C..........Yl7...qG
0360 e1 d8 06 1a 4d 4d 4d 2f 8a c2 21 84 10 94 95 69 c2 11 87 b6 76 45 32 4f 28 9f 8f 97 6d df b8 c6 ....MMM/..!....i....vE2O(...m...
0380 f5 4c ca 8a 0a da a6 7c 7b ea 83 5b 40 60 4b d0 77 bd 6b 56 a6 f2 ee ef 5e bc 19 aa 8a c1 50 05 .L.....|{..[@`K.w.kV....^.....P.
03a0 0b 00 68 01 23 07 c0 c2 c7 b2 5c f5 60 31 cb 9a 2a 39 6b 60 6c e5 a4 fe 99 2f 76 27 d8 b4 ad 85 ..h.#.....\.`1..*9k`l..../v'....
03c0 ed 13 a6 9d 95 ba e6 f6 47 67 d6 d4 0d 38 bf 25 de e4 2e 6b f8 dc 5b db b8 4e 6e 68 58 67 ee d8 ........Gg...8.%...k..[..NnhXg..
03e0 fd 75 70 f5 f6 cd c1 ac 93 63 78 ef 4a ae 3f fd 4a 2e 3a e6 62 4c 6f 0f 3a bd 92 50 ee 3d d6 bf .up......cx.J.?.J.:.bLo.:..P.=..
0400 bf 92 3b 9e c8 d3 5c df 1e ee 13 8e a7 23 26 91 e6 24 2e 10 e8 36 9b 0e 04 20 2c ec f9 1b 82 35 ..;...\......#&..$...6....,....5
0420 f3 56 39 f7 9e 34 91 ba 8b 7f 54 f0 5b ed f9 ca 1b a0 8c c2 d3 c3 fb 78 3c fc af 6d 5c f7 fb 4a .V9..4....T.[..........x<..m\..J
0440 16 ee 28 9f 70 d6 60 23 31 b6 6f c7 b6 53 cf 99 39 e8 d8 2b 1e 3d 27 5c 56 75 c8 dc cf e6 66 3e ..(.p.`#1.o..S..9..+.='\Vu....f>
0460 d9 fa bf 46 d8 0c 07 2d 29 a5 12 da 4c 39 6e d0 b0 4c 4e 1a 3d 91 59 e7 fd 86 71 83 26 e1 b5 3c ...F...-)...L9n..LN.=.Y...q.&..<
0480 8f 1b 7b 09 dd b1 1c 47 c3 b4 b1 a0 2e b7 b8 e2 fe b0 b1 a2 49 4c 2d 0b b1 61 43 ab 8e 03 61 7f ..{....G............IL-..aC...a.
04a0 e6 29 7f 2c 7b 5e bb 6e a3 f4 a8 67 cd 63 63 59 f7 6f 6b 9e 42 f6 af ee f9 bb 17 00 15 ec 5a 84 .).,{^.n...g.ccY.ok.B.........Z.
04c0 4d 03 56 6d 31 f9 c9 03 35 e4 32 da 39 e7 b0 d2 15 77 3f fb 7a 24 1c ad eb 7f cb 1b 77 ba 5a 1a M.Vm1...5.2.9....w?.z$......w.Z.
04e0 d6 c8 ea 11 d6 57 3b 57 b8 ab be 5e 69 ed 6a dd 1b d6 0a 86 56 f7 e2 f1 4b 1f 60 5c bf 31 b8 5f .....W;W...^i.j.....V...K.`\.1._
0500 df 84 6a 7b 1d ec 3c a6 53 18 20 e9 80 96 70 c6 1d f0 f7 e5 d8 02 ae ed 57 c6 86 fa 38 bb 80 98 ..j{..<.S.....p.........W...8...
0520 1f e4 9c 03 56 a1 8c 43 49 7d cc bd fb ae 0b 90 75 a5 3d 57 11 a5 0b c2 71 0b 4d 3b e0 e6 60 dc ....V..CI}......u.=W....q.M;..`.
0540 00 97 57 ee 6c c1 08 06 ac 51 a7 fd 7a 4a a4 a4 ef f0 5b 17 de 2e 6b 2a 6a 23 63 eb 46 07 fe b0 ..W.l....Q..zJ....[...k*j#c.F...
0560 f4 59 e7 bd 0d 8b 65 53 bc 2d a4 a5 41 65 99 c9 af 4f bd 92 71 03 27 e1 6e bd 09 d5 f2 0a da ce .Y....eS.-..Ae...O..q.'.n.......
0580 17 14 c8 83 cc 80 c8 83 cc c2 23 3f 85 70 80 80 10 5c b9 37 4d 91 1f e1 c3 fe 56 46 ee 1f 07 c4 ..........#?.p...\.7M.....VF....
05a0 d3 9f 71 c1 84 81 5c f5 d4 bf 14 9c 0d 7f 7d f7 7c b7 41 f8 eb bd ea ea 95 07 55 c5 9a 33 4f a8 ..q...\.......}.|.A.......U..3O.
05c0 63 fc b4 c7 c5 7f 7f fe 82 e1 4a cf 18 dc 6b a0 f1 bb 45 0f d8 59 3b 6d d8 b6 28 52 5a 8a 92 22 c.........J...k...E..Y;m..(RZ.."
05e0 97 d1 75 83 b9 eb ec d9 78 8d 7f 44 d5 3f 89 76 dd 7d b2 b4 07 d2 77 10 e1 41 65 31 b8 1e 7c bc ..u.....x..D.?.v.}....w..Ae1..|.
0600 9e ba c9 7d 49 34 24 d8 da 7d 61 de df 02 21 e0 8e 87 66 42 44 f8 eb b6 03 b9 0c c4 3a fc 09 63 ...}I4$..}a...!...fBD.......:..c
0620 17 46 be 7b c3 01 2f 0f 83 a7 dc 4b da db c1 ce cc 2e 31 a6 cf 38 6b fe 57 f3 71 94 6d 39 9e 8c .F.{../....K......1..8k.W.q.m9..
0640 28 29 44 b4 d8 43 5a 0e b7 9c 74 3d 64 ea 51 8d 2f a1 73 f9 42 1c 71 40 e7 c1 73 c1 d6 05 0b 08 ()D..CZ...t=d.Q./.s.B.q@..s.....
0660 b7 d0 6e 9d 0e 03 aa a0 21 c1 0c a0 cc df 6f 45 80 80 dc 6f 5b 71 e3 69 e3 18 70 c2 f0 82 e2 d2 ..n.....!.....oE...o[q.i..p.....
0680 05 3b 0b c7 3e 58 cd d5 ff 55 c5 8e 3d 02 4b 77 09 de d7 1c 10 56 2d ba ec 04 1a e2 1b 09 84 3c .;..>X...U..=.Kw.....V-........<
06a0 22 81 08 ab 5b b6 98 ae 36 83 ae 90 a2 28 ac 08 04 3c fa 95 d5 31 69 d0 11 78 6d 9f a3 f7 2c ef "...[...6....(...<...1i..xm...,.
06c0 21 c3 04 6c 07 56 6e 29 2c db 9d c1 31 22 60 ce 85 b0 3b 45 1d 70 4e 37 10 a1 ee 00 aa 2c 83 9b !..l.Vn),...1"`...;E.pN7.....,..
06e0 e7 9c d7 15 35 b1 c1 4b c1 b0 68 9a cf b6 84 b8 fe f9 2a 76 36 c9 82 89 1d 5f 71 a7 e0 b7 46 d5 ....5..K..h.......*v6...._q...F.
0700 d9 38 5e 86 b5 6d 9b 18 d4 6b 20 cd a9 9d b8 5a 0b 47 48 51 1c 56 44 c2 e0 68 87 53 47 4d 03 37 .8^..m...k.....Z.GHQ.VD..h.SGM.7
0720 8b de fd 7e 41 46 27 00 0f 52 49 b8 e7 2f 65 9c fc 40 19 8b 57 17 94 17 be 75 66 8c 87 93 47 03 ...~AF'..RI../e..@..W....uf...G.
0740 70 21 50 0b 94 00 91 ee 00 ee b8 fa 58 ca 86 f7 2a 08 ec 9c a4 af 7e 01 6e 2e ad 4f 1f 10 5f b3 p!P.........X...*.....~.n..O.._.
0760 6a 67 90 9f 3d 57 4d 5b bb d8 27 78 df ce bd 74 0a ae 9b 67 5d db 46 6a 4b ea d8 93 de 45 34 e2 jg..=WM[..'x...t...g].FjK....E4.
0780 12 09 2a 22 21 0d 52 e0 a2 98 50 37 0e dc 3c 7a f7 a7 e0 75 b9 a1 97 83 db 5f 2e 67 ee a7 25 4c ..*"!.R...P7..<z...u....._.g..%L
07a0 e9 4b e2 c9 45 a0 7c 2b 08 1f c8 23 e7 43 d0 a4 08 b8 c4 07 50 d4 09 a0 7f 49 88 5f dc 39 ad 4b .K..E.|+...#.C......P....I._.9.K
07c0 71 1c 48 24 e1 e1 f7 a0 2d c3 aa a3 7a 77 2c 3a 6d 40 c7 a7 db 77 9b fa 8c 47 7b d3 1a 13 fb 2c q.H$....-...zw,:m@...w...G{....,
07e0 81 0d 22 dc 17 a5 15 29 95 23 1a 8c b2 ab a3 01 2b e0 11 8d 28 b4 14 68 09 4a 28 6a a3 35 85 59 .."....).#......+...(..h.J(j.5.Y
0800 df d1 52 d8 cc b9 e0 66 e1 ba b9 15 bc fc 45 94 29 b5 99 cd 3f 1b 93 7c 21 95 c5 79 e5 f3 9e 1b ..R....f......E.)...?..|!..y....
0820 c0 a1 e5 70 d5 31 00 4c 03 86 76 b7 c0 6d 37 1d 47 a8 3a c4 3e b3 6a 07 e6 2c 86 fa 76 1c c7 e3 ...p.1.L..v..m7.G.:.>.j..,..v...
0840 af db da 68 38 73 44 7c c1 69 83 d3 ef ef 49 4a 75 f6 d3 bd d9 b8 cb c4 f0 7c 0b 04 aa fd bd b2 ...h8sD|.i....IJu........|......
0860 c4 55 2e 2d e9 26 14 0a a4 40 c8 c2 36 5b 09 4d 65 a4 17 5a 29 74 2a 8b a5 21 96 80 6b e6 55 f2 .U.-.&...@..6[.Me..Z)t*..!..k.U.
0880 fa ca 62 8e e8 93 d9 74 c3 84 b6 3f f7 2b 57 1f e4 5c 5e 9d fd 36 a4 52 fe 80 fa 83 75 e7 89 50 ..b....t...?.+W..\^..6.R....u..P
08a0 14 c0 04 2e 00 c2 12 a8 29 0e f0 f3 6b 0f ef b9 e6 b7 27 e0 b1 8f 21 ef f1 c1 9e 14 db b7 c6 68 ........)...k.....'...!........h
08c0 69 8e b1 f3 fa a3 db e7 cd 1c 95 7a bd 35 29 f5 95 f3 aa f8 62 bb 85 e5 81 90 16 02 41 28 10 a6 i..........z.5).....b.......A(..
08e0 25 dd 4c d2 49 80 2c 04 23 64 61 e3 ae a5 c6 92 16 a0 b1 5c 68 d8 23 b9 e1 b5 4a de 5e 1f 61 6a %.L.I.,.#da........\h.#...J.^.aj
0900 bf d4 ba 1b 27 b6 fd 19 4b af 72 6c be 3e bc 2f bf dd d1 4e c7 b3 9f f8 2e ed eb 55 15 84 ab 8e ....'...K.rl.>./...N.......U....
0920 00 e0 47 40 7f 09 5c fe f3 89 04 2b ac 9e 00 9e 5e 0a a9 3c ca 55 bc dd 9a 22 bb bd 8d d8 ce 38 ..G@..\....+....^..<.U...".....8
0940 bb b2 1d d4 df f3 a3 c4 fc 5b 0f 4f cc 6b 49 48 7d ed fc 2a 96 ef f0 73 02 04 d1 50 29 9b 63 1b .........[.O.kIH}..*...s...P).c.
0960 88 e5 63 85 98 e1 67 c6 da a7 00 b4 d6 08 0d cd 6d 70 d3 82 5e bc bb 39 cc 8c 21 c9 55 d7 4c 88 ..c...g.........mp..^..9..!.U.L.
0980 bd 26 84 5e 2b 3c 76 58 8a dd 37 1f 41 bd a7 79 ee e1 8f 0a 4b 74 77 dd 7e 35 65 5f 2e 33 5d 02 .&.^+<vX..7.A..y....Ktw.~5e_.3].
09a0 e7 cc 18 d1 15 5d 3b db ab 6b 0b 9b 4e 57 d1 92 72 c8 37 a5 c9 ec 4c 90 48 d8 ec 11 8a 96 2b c6 .....];..k..NW..r.7...L.H.....+.
09c0 a5 96 de 7b 74 fb 1b 89 2c fa e2 97 22 24 32 e0 69 8f 45 3b de e2 cd 6d 7f c5 13 1e da b7 80 96 ...{t...,..."$2.i.E;...m........
09e0 20 64 57 f6 91 76 04 97 bf 12 e0 93 1d 21 7e 32 3a b9 fe 67 63 e2 4b 02 92 af 0d 49 63 48 d0 3a .dW..v.......!~2:..gc.K....IcH.:
0a00 2c 42 b2 5f 0b b6 a3 78 a3 a5 03 be 6a ec 09 60 60 31 f4 2f 05 60 92 04 2a 63 1d 07 26 1f 91 42 ,B._...x....j..``1./.`..*c..&..B
0a20 8c 0e 53 98 72 e4 5c 74 2c 85 97 ca e0 66 6c 6c 13 b2 33 47 65 be 3e b1 7f ae be b9 c3 24 69 9b ..S.r.\t,....fll..3Ge.>......$i.
0a40 a0 35 71 3b 4e 5e db 68 29 c0 10 fb dc a8 d3 95 84 80 8e 9c 64 69 7d 88 43 ab f3 1d 67 0e 49 d5 .5q;N^.h)...........di}.C...g.I.
0a60 87 2c 3a 50 a4 2c c8 94 95 93 eb 13 c5 d5 43 d0 c0 a1 21 13 86 95 f4 d4 6d 57 0c 1a 12 00 34 4b .,:P.,........C...!.....mW....4K
0a80 e0 8d 17 57 1f 08 e0 f2 b1 00 0c 94 30 d2 00 19 91 04 c2 01 22 42 10 01 22 79 4d f4 ee 4f cb 0f ...W........0......."B.."yM..O..
0aa0 7b 73 5b d1 80 d3 07 67 a8 0c bb 68 ed 2b 2a 44 21 47 16 ba 30 fa 46 17 08 ad a1 22 a4 f8 d5 61 {s[....g...h.+*D!G..0.F...."...a
0ac0 49 bd 72 4f 30 fa f4 aa f2 d1 c9 bc 2c b7 4c 8a 90 44 32 59 82 8d 1e c6 ac 77 31 05 5c 7b d9 21 I.rO0.......,.L..D2Y.....w1.\{.!
0ae0 10 95 3d bd e3 d9 e5 fb 78 96 0f 24 f0 c8 9b 5b 71 56 37 f7 04 70 d9 70 e8 17 05 04 e7 16 07 08 ..=.....x..$...[qV7..p.p........
0b00 55 46 29 a9 8d d2 2b 18 a0 56 47 a8 bd 6d 49 c5 59 2f ae 2b fe d1 d1 75 39 7e 3f d5 25 62 76 cb UF)...+..VG..mI.Y/.+...u9~?.%bv.
0b20 b2 0d 81 36 40 48 51 00 d1 9d 02 d3 10 90 9a db 26 21 2e 1d d5 c1 92 c6 70 ff 47 bf ac 38 c5 f1 ...6@HQ.........&!......p.G..8..
0b40 18 82 a4 4f de a5 6a 57 3b 25 4f ac e6 62 53 32 f4 e6 09 3d f5 4a 65 e0 c9 2f 0b 1b 67 60 89 04 ...O..jW;%O..bS2...=.Je../..g`..
0b60 ea 35 bc 3a eb d3 9e 7f 0c 28 b8 ef 70 50 9a f1 b1 2c 87 ea 66 82 45 31 7a 59 09 6a 7f 3e 97 cb .5.:.....(..pP...,..f.E1zY.j.>..
0b80 5f 5c e1 9c 34 3e b2 9b 39 87 b6 52 eb 15 26 67 17 9d a5 41 08 b4 14 fb 40 20 f4 be 39 a0 95 a6 _\..4>..9..R..&g...A....@...9...
0ba0 28 0b 77 8f 89 73 6e 5d 23 4b b6 d8 43 af 7f c7 bc b4 7d 17 23 93 5b a8 79 f7 4d 2a e2 59 66 5d (.w..sn]#K..C.....}.#.[.y.M*.Yf]
0bc0 31 1a 86 45 7b ea f5 f8 72 88 15 98 a5 b7 80 5c 67 3e 30 02 58 f3 ce 74 ac 53 fb f9 df 8c 3c 11 1..E{...r......\g>0.X..t.S....<.
0be0 7d e6 7d 34 b8 51 5c 0c af aa 57 79 9b 29 95 b0 6d 37 d8 96 cc 46 11 88 ea 90 4b b1 05 1a 0d c1 }.}4.Q\...Wy.)..m7...F....K.....
0c00 12 d2 5e 96 51 0b 8f a6 cc 2c 2d 50 27 1a f0 f4 3e 1a 25 9e 4b b0 fe c2 4f 89 98 61 c8 25 11 42 ..^.Q....,-P'...>.%.K...O..a.%.B
0c20 90 73 a1 35 67 62 2b a1 cb 22 56 b6 24 1a ee 48 a4 72 e1 44 32 55 32 b0 18 0c 3b 85 5e 78 17 62 .s.5gb+.."V.$..H.r.D2U2...;.^x.b
0c40 c3 bb 34 a4 60 c4 cb 90 75 69 01 7e 01 d4 77 06 b2 4d c0 13 37 2e 05 3b e7 b3 0c 22 8c 08 44 a8 ..4.`...ui.~..w..M..7..;..."..D.
0c60 ed 55 46 b4 b8 d8 b0 55 be 2c e6 64 4b f7 3a f9 12 22 42 54 94 7a a8 90 24 29 25 1d d2 20 ed 66 .UF....U.,.dK.:.."BT.z..$)%....f
0c80 79 ab 69 31 01 d3 2a b8 0d e0 68 c8 2a 89 16 a0 85 20 60 04 78 bb 7e 31 19 27 4b 87 34 48 0a 89 y.i1..*...h.*.....`.x.~1.'K.4H..
0ca0 6d 49 ca a2 0a 33 ac 45 bb eb 44 5a 52 a9 5e 1e 2a da bb a2 04 23 52 8a 36 83 08 65 82 03 b3 96 mI...3.E..DZR.^.*....#R.6..e....
0cc0 41 b6 c0 0c bd e8 33 7a e9 ee 19 59 19 b0 f1 e1 49 d4 dc 38 c6 4f de 87 4f 86 33 ee 24 5d 37 81 A.....3z...Y....I..8.O..O.3.$]7.
0ce0 37 da 3e e2 a1 af ff 40 9e 1c 55 01 83 8c 93 22 96 6b 23 e3 64 30 b4 44 28 81 85 45 b1 11 01 a5 7.>....@..U....".k#.d0.D(..E....
0d00 c9 db 82 a4 63 a0 14 44 a5 47 c4 d0 48 2d c8 e4 33 d8 9e dd 95 4f f8 8c a8 56 8a 44 ce 60 40 74 ....c..D.G..H-..3....O...V.D.`@t
0d20 18 b7 1d 7e 0d 17 8e 98 8a a8 5f 89 5e 70 2f 6c 5d c9 ca 38 4c 79 0b 3c c5 16 e0 3a a0 05 d8 b3 ...~......_.^p/l]..8Ly.<...:....
0d40 3f 8b 7c 75 79 80 a7 36 9f 01 bd c2 05 d9 b2 a6 98 f7 47 dc c0 a0 e3 af 20 53 9c 66 f1 9e bf d1 ?.|uy..6..........G......S.f....
0d60 a8 f7 30 3c 3a 92 f6 7c 8c 55 b1 95 6c 68 5f 4b da 4e 63 61 21 b4 20 e7 40 87 23 11 1a 2d b4 46 ..0<:..|.U..lh_K.Nca!...@.#..-.F
0d80 b9 42 14 4b 45 c4 d0 08 25 7c 22 4c a3 95 46 68 81 e7 b9 18 98 5c 30 e4 1c ce 1f 73 05 46 2e c2 .B.KE...%|"L..Fh.....\0....s.F..
0da0 9e 17 6e e4 c8 3d 0b 21 65 83 80 b3 97 c0 db 4d e0 2a ee 00 96 00 bb 81 b6 fd 33 b2 d5 1a ce df ..n..=.!e......M.*........3.....
0dc0 9b a5 f2 cc 6a 90 0a 32 71 9b de 9b 3f e6 8d 57 5e e4 c4 a9 a7 30 79 d0 34 22 9e 60 61 eb df a9 ....j..2q...?..W^....0y.4".`a...
0de0 8e f4 e1 c4 de 27 31 bc 74 24 11 33 c2 d6 d4 66 6c cf 20 e5 99 68 a1 75 38 a4 6d cb c2 51 4a c8 .....'1.t$.3...fl....h.u8.m..QJ.
0e00 9c 27 a4 00 02 86 46 fb fc a3 40 92 f1 b2 f4 2f ee cb bf 1f 75 2f 17 8e be 88 aa bd 5b 58 31 eb .'....F...@..../....u/......[X1.
0e20 62 c6 37 2f c5 ca 7b 48 05 ef ec 82 39 5b c0 34 58 63 7b fc c9 cf 89 e3 40 7a 7f 00 6a 6c 6f 1a b.7/..{H....9[.4Xc{.....@z..jlo.
0e40 3f da cd 45 d3 2a a0 8f 09 96 82 a0 86 b1 e1 2c c1 4d 7f 43 16 55 31 60 e8 e9 4c 2d 99 cc 07 ad ?..E.*.........,.M.C.U1`..L-....
0e60 1f b2 3a b5 91 89 e5 13 19 56 32 9c ea 50 3f 3e 68 5d 85 94 5a 07 83 e4 b4 89 a3 0d 3c 69 68 4f ..:......V2..P?>h]..Z.......<ihO
0e80 6b 21 f3 9e 94 5a 6b 82 86 46 6b c8 aa 3c e7 0c 9c ce 63 47 3d c0 f0 f2 e1 c8 65 2f c3 8b d7 30 k!...Zk..Fk..<....cG=.....e/...0
0ea0 30 de 4c d8 77 b1 9c 03 57 af 05 d3 c2 8b 06 f9 fd de 0c 9b 7d 00 1d 40 ee 00 6e f4 cd cb a8 5f 0.L.w...W...........}..@..n...._
0ec0 bc 8d 23 17 d4 33 e8 f2 3e 85 cc 19 0d a6 06 95 b5 d1 ab 16 41 6c 3b 91 31 a7 70 42 e5 f1 b4 64 ..#..3..>...........Al;.1.pB...d
0ee0 1a 59 d4 fa 1e b5 e1 01 f4 29 1a c8 c0 e2 be 7a 63 6e 7d ce 95 ca f6 84 74 95 10 9e 30 84 67 59 .Y.......).....zcn}.....t...0.gY
0f00 5a 69 85 99 57 42 2a 25 a8 0e 15 71 cb d8 5f 71 d3 98 5f 12 f6 3c f4 bc 1b d1 0b 1e 43 c4 ed 7d Zi..WB*%...q.._q.._..<......C..}
0f20 39 31 1e dc b4 d1 60 45 d6 a4 57 58 2d 1f 58 ce 5b 1b 5b 69 04 92 9d ac c4 01 00 9e 9d 4e e9 96 91....`E..WX-.X.[.[i.........N..
0f40 84 fc e2 a3 26 73 66 32 a7 83 27 97 17 46 42 7b 85 ac 49 78 a0 1b 37 a2 97 cf 47 d6 0e 67 e2 90 ....&sf2..'..FB{..Ix..7...G..g..
0f60 1f 53 6e 56 f2 7c fd 02 5c e1 e8 09 95 63 bc 01 d1 01 7a 75 7a a3 9d 97 b6 07 68 85 d0 08 90 a6 .SnV.|..\....c....zuz.....h.....
0f80 72 b5 92 e6 e8 92 b1 72 f6 c4 bb 98 de e7 04 c4 ba f7 f1 e6 9c 8f 58 f7 25 32 df c5 f8 08 05 1b r......r..............X.%2......
0fa0 53 70 c3 16 8b bd 19 d5 61 4a 66 0f 2a 63 ef 9a dd 34 f9 ec 5c 9e 02 d7 d0 f3 ba e7 64 94 65 5a Sp......aJf.*c...4..\.......d.eZ
0fc0 72 c1 26 d3 fd a4 cd 3b f6 e4 12 4d 5f ab 8b 61 ee 64 0d 44 36 85 bb e2 4d de 6d 4c 53 37 e4 74 r.&....;...M_..a.d.D6...M.mLS7.t
0fe0 ce ea 77 22 eb b3 6b f3 5f 74 ac 72 86 96 0c 95 a5 56 19 eb d3 5b 1c 55 08 70 22 eb e5 a9 0c f6 ..w"..k._t.r.....V...[.U.p".....
1000 12 d7 0e bf cc bb 6b f4 cd 16 f1 22 f1 f7 e7 1f 61 f0 9f 7f 43 30 91 45 74 53 be f3 3d 37 6c 85 ......k...."....a...C0.EtS..=7l.
1020 15 ed 0a 84 98 5b 55 24 96 8f af d1 e9 cf 1a 69 06 b2 7e 68 3b 90 5e ff b7 e3 28 1e 51 e9 b5 37 .....[U$.......i..~h;.^...(.Q..7
1040 a4 23 db 97 37 b8 47 7e 96 0d d6 fd b4 cc 25 a0 bb 46 c6 56 f0 55 3b 2c 88 87 b8 e3 c3 9d 34 6c .#..7.G~......%..F.V.U;,......4l
1060 f8 30 7f f8 98 51 b9 33 46 5d 10 2c 72 23 2c 68 59 a4 23 66 91 b9 31 b6 c5 b4 5d 37 90 b3 f3 81 .0...Q.3F].,r#,hY.#f..1...]7....
1080 29 c5 13 ac fb 87 dd 1e bc 60 c0 8f 43 2d 1b 96 67 9e 7e f0 7a ef b1 79 6f cb 6a d3 95 23 2d 08 )........`..C-..g.~.z..yo.j..#-.
10a0 78 5d 6e 23 14 2c 68 87 bb b7 81 34 cc ed d1 a0 78 e6 e2 f1 8a 2f 1a d9 bc 33 4e c2 4f a1 d4 41 x]n#.,h....4....x..../...3N.O..A
10c0 01 fc 76 2a 61 c7 40 4e ae cb 77 2c de 66 ad 58 bb d7 9d d9 ec 9a 81 e9 c5 1e d2 4f ef 4c 0f 76 ..v*a.@N..w,.f.X...........O.L.v
10e0 66 04 0f ee 94 98 61 4d 8d b3 cd 9c ff da 2b 81 86 96 36 39 e3 84 4b cc a3 42 93 ac 4f f7 7c 6e f.....aM......+...69..K..B..O.|n
1100 ae 4c ac 0d 68 5b 05 66 d6 cc b0 1e 1a 76 b7 35 38 3a d0 9c 33 fb 76 79 ff 9d 37 07 5b b7 34 5a .L..h[.f.....v.58:..3.vy..7.[.4Z
1120 a3 0d 57 6e 49 c2 d1 21 28 97 fe 00 69 68 cc c3 b4 35 60 23 9d 90 a9 ef af 89 78 5b 3f ab 67 5b ..WnI..!(...ih...5`#......x[?.g[
1140 df 52 d2 db 63 64 3a 79 d1 83 56 68 f4 bd 44 3c 0b e9 68 42 4d 1e ce 21 f7 89 6b 1d 8f fb fe 34 .R..cd:y..Vh..D<..hBM..!..k....4
1160 c4 60 66 89 5b d8 8f e9 82 b5 53 48 bc 6a a8 74 15 1d b9 42 e2 21 47 4d 26 70 c3 a3 98 75 83 59 .`f.[.....SH.j.t...B.!GM&p...u.Y
1180 b8 7b 11 00 67 d6 9c 82 de b5 1d f7 d1 5f 13 da b4 1c ed 5b b2 b3 52 a1 34 64 11 14 09 4d de 80 .{..g........_.....[..R.4d...M..
11a0 93 d7 c3 27 69 81 21 98 3f b9 bf fe 53 43 8c 9d a7 0c 27 35 b2 82 f4 2d ff c3 de ee f4 fa 01 16 ...'i.!.?...SC....'5...-........
11c0 b8 eb 48 c8 06 b1 02 02 55 a4 09 f6 ed cd d2 05 6b 98 f6 71 52 f7 39 a2 c8 a4 1f 6a 1f 8b 16 d6 ..H.....U.......k..qR.9....j....
11e0 9a 22 ad d1 39 08 da 10 74 21 d4 dc 84 b1 e4 0d 64 45 35 a3 86 1c c7 c8 40 3f c4 47 0b 91 f7 fd ."..9...t!......dE5.....@?.G....
1200 12 6b c7 d6 ae 4a 8d 02 61 16 46 b0 cd 91 e0 0a f2 0a 66 35 c2 6b 69 8b a0 a1 9b 2f 98 a0 9f 89 .k...J..a.F.......f5.ki..../....
1220 75 d0 38 be 0f e9 f1 7d c8 46 4b 49 2e 5c 87 fd ad 35 32 7d 37 12 81 69 0b 42 96 89 6e ed 40 1c u.8....}.FKI.\...52}7..i.B..n.@.
1240 f6 0c d5 8d 09 96 8d 0d 89 8a f9 7d 05 83 2d 85 90 20 03 a0 73 85 fd 7e 81 f9 dd 4f d8 71 67 14 ...........}..-.....s..~...O.qg.
1260 ea 66 1f 2e ec 51 4f 15 a2 c0 72 63 fa 29 67 00 b6 a6 4c 5e df ab b8 37 19 c4 50 76 fe 90 6a ef .f...QO...rc.)g...L^...7..Pv..j.
1280 0e 29 58 be 37 43 f3 45 63 b1 23 82 b6 29 7d c9 1e ff 42 cf 3a d9 41 4b 72 ea 33 a4 f8 1c 93 0c .)X.7C.Ec.#..)}...B.:.AKr.3.....
12a0 c1 bc 87 da d2 8a 3c ea 69 ce ca 38 cc 1d 5a 24 38 21 ac 19 2c a0 4f 11 94 6a 08 ab c2 de 49 6b ......<.i..8..Z$8!..,.O..j....Ik
12c0 28 96 7e ec d8 af b6 9a 56 90 d5 90 53 90 d2 e0 c9 42 28 6d 03 76 2b f8 32 0b b2 d8 a0 21 ae a8 (.~.....V...S....B(m.v+.2....!..
12e0 08 e9 e7 6a 4b 78 e9 eb 76 5a a6 8f c4 0e 08 62 a3 aa 49 5f d5 82 2b 96 f5 ac 91 7d 63 4d 51 2d ...jKx..vZ.....b..I_..+....}cMQ-
1300 45 8a 0f 31 94 45 80 0c c6 1f bf c2 fe cd 22 6e c8 da dc 5f 1a 42 c4 73 e0 15 58 13 1c 5f f9 ef E..1.E........"n..._.B.s..X.._..
1320 7d 3e c0 b7 82 25 0b 2d 60 40 d0 04 db c3 2b 0b f3 97 49 75 3c f7 55 13 2d 23 6a c8 14 87 48 0d }>...%.-`@....+...Iu<.U.-#j...H.
1340 8b 92 be 27 87 23 97 1d f8 8a 1f 5a a9 37 81 43 80 63 80 c1 3e c5 57 ed e7 ce 9d f2 3a a9 ef fd ...'.#.....Z.7.C.c..>.W.....:...
1360 af 0e df 83 92 fe 24 ec f0 fb 3d 7e 76 d5 00 ac f5 7f ef 2c 88 e7 fc 7b ef 9b aa f5 ff 9f a3 06 ......$...=~v......,...{........
1380 f2 20 47 0d 8c 6e 47 0b be ed 9c 84 3e 48 af 0f 72 d4 a0 33 03 f6 fe 99 47 0d 0e 06 a4 fb a1 8f ..G..nG.....>H..r..3....G.......
13a0 ef 73 7a 45 7f c7 7d f7 4a b3 fe 3e a7 56 fe d1 e3 31 df f7 64 ca 77 9d 56 e1 87 1e b3 e9 bc fe .szE..}.J..>.V...1..d.w.V.......
13c0 0f 08 9b 4d e1 53 97 1d 34 00 00 00 00 49 45 4e 44 ae 42 60 82 ...M.S..4....IEND.B`.
'>1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608
/* X-Chat
 * Copyright (C) 2002 Peter Zelezny.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

/* IRC RFC1459(+commonly used extensions) protocol implementation */

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdarg.h>

#ifndef WIN32
#include <unistd.h>
#endif

#include "hexchat.h"
#include "proto-irc.h"
#include "ctcp.h"
#include "fe.h"
#include "ignore.h"
#include "inbound.h"
#include "modes.h"
#include "notify.h"
#include "plugin.h"
#include "server.h"
#include "text.h"
#include "outbound.h"
#include "util.h"
#include "hexchatc.h"
#include "url.h"
#include "servlist.h"

static void
irc_login (server *serv, char *user, char *realname)
{
	tcp_sendf (serv, "CAP LS\r\n");		/* start with CAP LS as Charybdis sasl.txt suggests */
	serv->sent_capend = FALSE;	/* track if we have finished */

	if (serv->password[0] && serv->loginmethod == LOGIN_PASS)
	{
		tcp_sendf (serv, "PASS %s\r\n", serv->password);
	}

	tcp_sendf (serv,
				  "NICK %s\r\n"
				  "USER %s %s %s :%s\r\n",
				  serv->nick, user, user, serv->servername, realname);
}

static void
irc_nickserv (server *serv, char *cmd, char *arg1, char *arg2, char *arg3)
{
	/* are all ircd authors idiots? */
	switch (serv->loginmethod)
	{
		case LOGIN_MSG_NICKSERV:
			tcp_sendf (serv, "PRIVMSG NICKSERV :%s %s%s%s\r\n", cmd, arg1, arg2, arg3);
			break;
		case LOGIN_NICKSERV:
			tcp_sendf (serv, "NICKSERV %s %s%s%s\r\n", cmd, arg1, arg2, arg3);
			break;
		default: /* This may not work but at least it tries something when using /id or /ghost cmd */
			tcp_sendf (serv, "NICKSERV %s %s%s%s\r\n", cmd, arg1, arg2, arg3);
			break;
#if 0
		case LOGIN_MSG_NS:
			tcp_sendf (serv, "PRIVMSG NS :%s %s%s%s\r\n", cmd, arg1, arg2, arg3);
			break;
		case LOGIN_NS:
			tcp_sendf (serv, "NS %s %s%s%s\r\n", cmd, arg1, arg2, arg3);
			break;
		case LOGIN_AUTH:
			/* why couldn't QuakeNet implement one of the existing ones? */
			tcp_sendf (serv, "AUTH %s %s\r\n", arg1, arg2);
			break;
#endif
	}
}

static void
irc_ns_identify (server *serv, char *pass)
{
	switch (serv->loginmethod)
	{
		case LOGIN_CHALLENGEAUTH:
			tcp_sendf (serv, "PRIVMSG %s :CHALLENGE\r\n", CHALLENGEAUTH_NICK);	/* request a challenge from Q */
			break;
#if 0
		case LOGIN_AUTH:
			irc_nickserv (serv, "", serv->nick, pass, "");
			break;
#endif
		default:
			irc_nickserv (serv, "IDENTIFY", pass, "", "");
	}
}

static void
irc_ns_ghost (server *serv, char *usname, char *pass)
{
	if (serv->loginmethod != LOGIN_CHALLENGEAUTH)
	{
		irc_nickserv (serv, "GHOST", usname, " ", pass);
	}
}

static void
irc_join (server *serv, char *channel, char *key)
{
	if (key[0])
		tcp_sendf (serv, "JOIN %s %s\r\n", channel, key);
	else
		tcp_sendf (serv, "JOIN %s\r\n", channel);
}

static void
irc_join_list_flush (server *serv, GString *channels, GString *keys, int send_keys)
{
	char *chanstr;
	char *keystr;

	chanstr = g_string_free (channels, FALSE);				/* convert our strings to char arrays */
	keystr = g_string_free (keys, FALSE);

	if (send_keys)
	{
		tcp_sendf (serv, "JOIN %s %s\r\n", chanstr, keystr);	/* send the actual command */
	}
	else
	{
		tcp_sendf (serv, "JOIN %s\r\n", chanstr);	/* send the actual command */
	}

	g_free (chanstr);
	g_free (keystr);
}

/* Join a whole list of channels & keys, split to multiple lines
 * to get around the 512 limit.
 */

static void
irc_join_list (server *serv, GSList *favorites)
{
	int first_item = 1;										/* determine whether we add commas or not */
	int send_keys = 0;										/* if none of our channels have keys, we can omit the 'x' fillers altogether */
	int len = 9;											/* JOIN<space>channels<space>keys\r\n\0 */
	favchannel *fav;
	GString *chanlist = g_string_new (NULL);
	GString *keylist = g_string_new (NULL);
	GSList *favlist;

	favlist = favorites;

	while (favlist)
	{
		fav = favlist->data;

		len += strlen (fav->name);
		if (fav->key)
		{
			len += strlen (fav->key);
		}

		if (len >= 512)										/* command length exceeds the IRC hard limit, flush it and start from scratch */
		{
			irc_join_list_flush (serv, chanlist, keylist, send_keys);

			chanlist = g_string_new (NULL);
			keylist = g_string_new (NULL);

			len = 9;
			first_item = 1;									/* list dumped, omit commas once again */
			send_keys = 0;									/* also omit keys until we actually find one */
		}

		if (!first_item)
		{
			/* This should be done before the length check, but channel names
			 * are already at least 2 characters long so it would trigger the
			 * flush anyway.
			 */
			len += 2;

			/* add separators but only if it's not the 1st element */
			g_string_append_c (chanlist, ',');
			g_string_append_c (keylist, ',');
		}

		g_string_append (chanlist, fav->name);

		if (fav->key)
		{
			g_string_append (keylist, fav->key);
			send_keys = 1;
		}
		else
		{
			g_string_append_c (keylist, 'x');				/* 'x' filler for keyless channels so that our JOIN command is always well-formatted */
		}

		first_item = 0;
		favlist = favlist->next;
	}

	irc_join_list_flush (serv, chanlist, keylist, send_keys);
	g_slist_free (favlist);
}

static void
irc_part (server *serv, char *channel, char *reason)
{
	if (reason[0])
		tcp_sendf (serv, "PART %s :%s\r\n", channel, reason);
	else
		tcp_sendf (serv, "PART %s\r\n", channel);
}

static void
irc_quit (server *serv, char *reason)
{
	if (reason[0])
		tcp_sendf (serv, "QUIT :%s\r\n", reason);
	else
		tcp_send_len (serv, "QUIT\r\n", 6);
}

static void
irc_set_back (server *serv)
{
	tcp_send_len (serv, "AWAY\r\n", 6);
}

static void
irc_set_away (server *serv, char *reason)
{
	if (reason)
	{
		if (!reason[0])
			reason = " ";
	}
	else
	{
		reason = " ";
	}

	tcp_sendf (serv, "AWAY :%s\r\n", reason);
}

static void
irc_ctcp (server *serv, char *to, char *msg)
{
	tcp_sendf (serv, "PRIVMSG %s :\001%s\001\r\n", to, msg);
}

static void
irc_nctcp (server *serv, char *to, char *msg)
{
	tcp_sendf (serv, "NOTICE %s :\001%s\001\r\n", to, msg);
}

static void
irc_cycle (server *serv, char *channel, char *key)
{
	tcp_sendf (serv, "PART %s\r\nJOIN %s %s\r\n", channel, channel, key);
}

static void
irc_kick (server *serv, char *channel, char *nick, char *reason)
{
	if (reason[0])
		tcp_sendf (serv, "KICK %s %s :%s\r\n", channel, nick, reason);
	else
		tcp_sendf (serv, "KICK %s %s\r\n", channel, nick);
}

static void
irc_invite (server *serv, char *channel, char *nick)
{
	tcp_sendf (serv, "INVITE %s %s\r\n", nick, channel);
}

static void
irc_mode (server *serv, char *target, char *mode)
{
	tcp_sendf (serv, "MODE %s %s\r\n", target, mode);
}

/* find channel info when joined */

static void
irc_join_info (server *serv, char *channel)
{
	tcp_sendf (serv, "MODE %s\r\n", channel);
}

/* initiate userlist retreival */

static void
irc_user_list (server *serv, char *channel)
{
	if (serv->have_whox)
		tcp_sendf (serv, "WHO %s %%chtsunfra,152\r\n", channel);
	else
		tcp_sendf (serv, "WHO %s\r\n", channel);
}

/* userhost */

static void
irc_userhost (server *serv, char *nick)
{
	tcp_sendf (serv, "USERHOST %s\r\n", nick);
}

static void
irc_away_status (server *serv, char *channel)
{
	if (serv->have_whox)
		tcp_sendf (serv, "WHO %s %%chtsunfra,152\r\n", channel);
	else
		tcp_sendf (serv, "WHO %s\r\n", channel);
}

/*static void
irc_get_ip (server *serv, char *nick)
{
	tcp_sendf (serv, "WHO %s\r\n", nick);
}*/


/*
 *  Command: WHOIS
 *     Parameters: [<server>] <nickmask>[,<nickmask>[,...]]
 */
static void
irc_user_whois (server *serv, char *nicks)
{
	tcp_sendf (serv, "WHOIS %s\r\n", nicks);
}

static void
irc_message (server *serv, char *channel, char *text)
{
	tcp_sendf (serv, "PRIVMSG %s :%s\r\n", channel, text);
}

static void
irc_action (server *serv, char *channel, char *act)
{
	tcp_sendf (serv, "PRIVMSG %s :\001ACTION %s\001\r\n", channel, act);
}

static void
irc_notice (server *serv, char *channel, char *text)
{
	tcp_sendf (serv, "NOTICE %s :%s\r\n", channel, text);
}

static void
irc_topic (server *serv, char *channel, char *topic)
{
	if (!topic)
		tcp_sendf (serv, "TOPIC %s :\r\n", channel);
	else if (topic[0])
		tcp_sendf (serv, "TOPIC %s :%s\r\n", channel, topic);
	else
		tcp_sendf (serv, "TOPIC %s\r\n", channel);
}

static void
irc_list_channels (server *serv, char *arg, int min_users)
{
	if (arg[0])
	{
		tcp_sendf (serv, "LIST %s\r\n", arg);
		return;
	}

	if (serv->use_listargs)
		tcp_sendf (serv, "LIST >%d,<10000\r\n", min_users - 1);
	else
		tcp_send_len (serv, "LIST\r\n", 6);
}

static void
irc_names (server *serv, char *channel)
{
	tcp_sendf (serv, "NAMES %s\r\n", channel);
}

static void
irc_change_nick (server *serv, char *new_nick)
{
	tcp_sendf (serv, "NICK %s\r\n", new_nick);
}

static void
irc_ping (server *serv, char *to, char *timestring)
{
	if (*to)
		tcp_sendf (serv, "PRIVMSG %s :\001PING %s\001\r\n", to, timestring);
	else
		tcp_sendf (serv, "PING %s\r\n", timestring);
}

static int
irc_raw (server *serv, char *raw)
{
	int len;
	char tbuf[4096];
	if (*raw)
	{
		len = strlen (raw);
		if (len < sizeof (tbuf) - 3)
		{
			len = snprintf (tbuf, sizeof (tbuf), "%s\r\n", raw);
			tcp_send_len (serv, tbuf, len);
		} else
		{
			tcp_send_len (serv, raw, len);
			tcp_send_len (serv, "\r\n", 2);
		}
		return TRUE;
	}
	return FALSE;
}

/* ============================================================== */
/* ======================= IRC INPUT ============================ */
/* ============================================================== */


static void
channel_date (session *sess, char *chan, char *timestr,
				  const message_tags_data *tags_data)
{
	time_t timestamp = (time_t) atol (timestr);
	char *tim = ctime (&timestamp);
	tim[24] = 0;	/* get rid of the \n */
	EMIT_SIGNAL_TIMESTAMP (XP_TE_CHANDATE, sess, chan, tim, NULL, NULL, 0,
								  tags_data->timestamp);
}

static void
process_numeric (session * sess, int n,
					  char *word[], char *word_eol[], char *text,
					  const message_tags_data *tags_data)
{
	server *serv = sess->server;
	/* show whois is the server tab */
	session *whois_sess = serv->server_session;
	
	/* unless this setting is on */
	if (prefs.hex_irc_whois_front)
		whois_sess = serv->front_session;

	switch (n)
	{
	case 1:
		inbound_login_start (sess, word[3], word[1], tags_data);
		/* if network is PTnet then you must get your IP address
			from "001" server message */
		if ((strncmp(word[7], "PTnet", 5) == 0) &&
			(strncmp(word[8], "IRC", 3) == 0) &&
			(strncmp(word[9], "Network", 7) == 0) &&
			(strrchr(word[10], '@') != NULL))
		{
			serv->use_who = FALSE;
			if (prefs.hex_dcc_ip_from_server)
				inbound_foundip (sess, strrchr(word[10], '@')+1, tags_data);
		}

		goto def;

	case 4:	/* check the ircd type */
		serv->use_listargs = FALSE;
		serv->modes_per_line = 3;		/* default to IRC RFC */
		if (strncmp (word[5], "bahamut", 7) == 0)				/* DALNet */
		{
			serv->use_listargs = TRUE;		/* use the /list args */
		} else if (strncmp (word[5], "u2.10.", 6) == 0)		/* Undernet */
		{
			serv->use_listargs = TRUE;		/* use the /list args */
			serv->modes_per_line = 6;		/* allow 6 modes per line */
		} else if (strncmp (word[5], "glx2", 4) == 0)
		{
			serv->use_listargs = TRUE;		/* use the /list args */
		}
		goto def;

	case 5:
		inbound_005 (serv, word, tags_data);
		goto def;

	case 263:	/*Server load is temporarily too heavy */
		if (fe_is_chanwindow (sess->server))
		{
			fe_chan_list_end (sess->server);
			fe_message (word_eol[4], FE_MSG_ERROR);
		}
		goto def;

	case 301:
		inbound_away (serv, word[4],
						  (word_eol[5][0] == ':') ? word_eol[5] + 1 : word_eol[5],
						  tags_data);
		break;

	case 302:
		if (serv->skip_next_userhost)
		{
			char *eq = strchr (word[4], '=');
			if (eq)
			{
				*eq = 0;
				if (!serv->p_cmp (word[4] + 1, serv->nick))
				{
					char *at = strrchr (eq + 1, '@');
					if (at)
						inbound_foundip (sess, at + 1, tags_data);
				}
			}

			serv->skip_next_userhost = FALSE;
			break;
		}
		else goto def;

	case 303:
		word[4]++;
		notify_markonline (serv, word, tags_data);
		break;

	case 305:
		inbound_uback (serv, tags_data);
		goto def;

	case 306:
		inbound_uaway (serv, tags_data);
		goto def;

	case 312:
		if (!serv->skip_next_whois)
			EMIT_SIGNAL_TIMESTAMP (XP_TE_WHOIS3, whois_sess, word[4], word_eol[5],
										  NULL, NULL, 0, tags_data->timestamp);
		else
			inbound_user_info (sess, NULL, NULL, NULL, word[5], word[4], NULL, NULL,
									 0xff, tags_data);
		break;

	case 311:	/* WHOIS 1st line */
		serv->inside_whois = 1;
		inbound_user_info_start (sess, word[4], tags_data);
		if (!serv->skip_next_whois)
			EMIT_SIGNAL_TIMESTAMP (XP_TE_WHOIS1, whois_sess, word[4], word[5],
										  word[6], word_eol[8] + 1, 0, tags_data->timestamp);
		else
			inbound_user_info (sess, NULL, word[5], word[6], NULL, word[4],
									 word_eol[8][0] == ':' ? word_eol[8] + 1 : word_eol[8],
									 NULL, 0xff, tags_data);
		break;

	case 314:	/* WHOWAS */
		inbound_user_info_start (sess, word[4], tags_data);
		EMIT_SIGNAL_TIMESTAMP (XP_TE_WHOIS1, whois_sess, word[4], word[5],
									  word[6], word_eol[8] + 1, 0, tags_data->timestamp);
		break;

	case 317:
		if (!serv->skip_next_whois)
		{
			time_t timestamp = (time_t) atol (word[6]);
			long idle = atol (word[5]);
			char *tim;
			char outbuf[64];

			snprintf (outbuf, sizeof (outbuf),
						"%02ld:%02ld:%02ld", idle / 3600, (idle / 60) % 60,
						idle % 60);
			if (timestamp == 0)
				EMIT_SIGNAL_TIMESTAMP (XP_TE_WHOIS4, whois_sess, word[4],
											  outbuf, NULL, NULL, 0, tags_data->timestamp);
			else
			{
				tim = ctime (&timestamp);
				tim[19] = 0; 	/* get rid of the \n */
				EMIT_SIGNAL_TIMESTAMP (XP_TE_WHOIS4T, whois_sess, word[4],
											  outbuf, tim, NULL, 0, tags_data->timestamp);
			}
		}
		break;

	case 318:	/* END OF WHOIS */
		if (!serv->skip_next_whois)
			EMIT_SIGNAL_TIMESTAMP (XP_TE_WHOIS6, whois_sess, word[4], NULL,
										  NULL, NULL, 0, tags_data->timestamp);
		serv->skip_next_whois = 0;
		serv->inside_whois = 0;
		break;

	case 313:
	case 319:
		if (!serv->skip_next_whois)
			EMIT_SIGNAL_TIMESTAMP (XP_TE_WHOIS2, whois_sess, word[4],
										  word_eol[5] + 1, NULL, NULL, 0,
										  tags_data->timestamp);
		break;

	case 307:	/* dalnet version */
	case 320:	/* :is an identified user */
		if (!serv->skip_next_whois)
			EMIT_SIGNAL_TIMESTAMP (XP_TE_WHOIS_ID, whois_sess, word[4],
										  word_eol[5] + 1, NULL, NULL, 0,
										  tags_data->timestamp);
		break;

	case 321:
		if (!fe_is_chanwindow (sess->server))
			EMIT_SIGNAL_TIMESTAMP (XP_TE_CHANLISTHEAD, serv->server_session, NULL,
										  NULL, NULL, NULL, 0, tags_data->timestamp);
		break;

	case 322:
		if (fe_is_chanwindow (sess->server))
		{
			fe_add_chan_list (sess->server, word[4], word[5], word_eol[6] + 1);
		} else
		{
			PrintTextTimeStampf (serv->server_session, tags_data->timestamp,
										"%-16s %-7d %s\017\n", word[4], atoi (word[5]),
										word_eol[6] + 1);
		}
		break;

	case 323:
		if (!fe_is_chanwindow (sess->server))
			EMIT_SIGNAL_TIMESTAMP (XP_TE_SERVTEXT, serv->server_session, text, 
										  word[1], word[2], NULL, 0, tags_data->timestamp);
		else
			fe_chan_list_end (sess->server);
		break;

	case 324:
		sess = find_channel (serv, word[4]);
		if (!sess)
			sess = serv->server_session;
		if (sess->ignore_mode)
			sess->ignore_mode = FALSE;
		else
			EMIT_SIGNAL_TIMESTAMP (XP_TE_CHANMODES, sess, word[4], word_eol[5],
										  NULL, NULL, 0, tags_data->timestamp);
		fe_update_mode_buttons (sess, 't', '-');
		fe_update_mode_buttons (sess, 'n', '-');
		fe_update_mode_buttons (sess, 's', '-');
		fe_update_mode_buttons (sess, 'i', '-');
		fe_update_mode_buttons (sess, 'p', '-');
		fe_update_mode_buttons (sess, 'm', '-');
		fe_update_mode_buttons (sess, 'l', '-');
		fe_update_mode_buttons (sess, 'k', '-');
		handle_mode (serv, word, word_eol, "", TRUE, tags_data);
		break;

	case 328: /* channel url */
		sess = find_channel (serv, word[4]);
		if (sess)
		{
			EMIT_SIGNAL_TIMESTAMP (XP_TE_CHANURL, sess, word[4], word[5] + 1,
									NULL, NULL, 0, tags_data->timestamp); 
		}
		break;

	case 329:
		sess = find_channel (serv, word[4]);
		if (sess)
		{
			if (sess->ignore_date)
				sess->ignore_date = FALSE;
			else
				channel_date (sess, word[4], word[5], tags_data);
		}
		break;

	case 330:
		if (!serv->skip_next_whois)
			EMIT_SIGNAL_TIMESTAMP (XP_TE_WHOIS_AUTH, whois_sess, word[4],
										  word_eol[6] + 1, word[5], NULL, 0,
										  tags_data->timestamp);
		inbound_user_info (sess, NULL, NULL, NULL, NULL, word[4], NULL, word[5],
								 0xff, tags_data);
		break;

	case 332:
		inbound_topic (serv, word[4],
							(word_eol[5][0] == ':') ? word_eol[5] + 1 : word_eol[5],
							tags_data);
		break;

	case 333:
		inbound_topictime (serv, word[4], word[5], atol (word[6]), tags_data);
		break;

#if 0
	case 338:  /* Undernet Real user@host, Real IP */
		EMIT_SIGNAL_TIMESTAMP (XP_TE_WHOIS_REALHOST, sess, word[4], word[5], word[6], 
									  (word_eol[7][0]==':') ? word_eol[7]+1 : word_eol[7],
									  0, tags_data->timestamp);
		break;
#endif

	case 341:						  /* INVITE ACK */
		EMIT_SIGNAL_TIMESTAMP (XP_TE_UINVITE, sess, word[4], word[5],
									  serv->servername, NULL, 0, tags_data->timestamp);
		break;

	case 352:						  /* WHO */
		{
			unsigned int away = 0;
			session *who_sess = find_channel (serv, word[4]);

			if (*word[9] == 'G')
				away = 1;

			inbound_user_info (sess, word[4], word[5], word[6], word[7],
									 word[8], word_eol[11], NULL, away,
									 tags_data);

			/* try to show only user initiated whos */
			if (!who_sess || !who_sess->doing_who)
				EMIT_SIGNAL_TIMESTAMP (XP_TE_SERVTEXT, serv->server_session, text, word[1],
											  word[2], NULL, 0, tags_data->timestamp);
		}
		break;

	case 354:	/* undernet WHOX: used as a reply for irc_away_status */
		{
			unsigned int away = 0;
			session *who_sess;

			/* irc_away_status and irc_user_list sends out a "152" */
			if (!strcmp (word[4], "152"))
			{
				who_sess = find_channel (serv, word[5]);

				if (*word[10] == 'G')
					away = 1;

				/* :server 354 yournick 152 #channel ~ident host servname nick H account :realname */
				inbound_user_info (sess, word[5], word[6], word[7], word[8],
										 word[9], word_eol[12]+1, word[11], away,
										 tags_data);

				/* try to show only user initiated whos */
				if (!who_sess || !who_sess->doing_who)
					EMIT_SIGNAL_TIMESTAMP (XP_TE_SERVTEXT, serv->server_session, text,
												  word[1], word[2], NULL, 0,
												  tags_data->timestamp);
			} else
				goto def;
		}
		break;

	case 315:						  /* END OF WHO */
		{
			session *who_sess;
			who_sess = find_channel (serv, word[4]);
			if (who_sess)
			{
				if (!who_sess->doing_who)
					EMIT_SIGNAL_TIMESTAMP (XP_TE_SERVTEXT, serv->server_session, text,
												  word[1], word[2], NULL, 0,
												  tags_data->timestamp);
				who_sess->doing_who = FALSE;
			} else
			{
				if (!serv->doing_dns)
					EMIT_SIGNAL_TIMESTAMP (XP_TE_SERVTEXT, serv->server_session, text,
												  word[1], word[2], NULL, 0, tags_data->timestamp);
				serv->doing_dns = FALSE;
			}
		}
		break;

	case 346:	/* +I-list entry */
		if (!inbound_banlist (sess, atol (word[7]), word[4], word[5], word[6], 346,
									 tags_data))
			goto def;
		break;

	case 347:	/* end of invite list */
		if (!fe_ban_list_end (sess, 347))
			goto def;
		break;

	case 348:	/* +e-list entry */
		if (!inbound_banlist (sess, atol (word[7]), word[4], word[5], word[6], 348,
									 tags_data))
			goto def;
		break;

	case 349:	/* end of exemption list */
		sess = find_channel (serv, word[4]);
		if (!sess)
		{
			sess = serv->front_session;
			goto def;
		}
		if (!fe_ban_list_end (sess, 349))
			goto def;
		break;

	case 353:						  /* NAMES */
		inbound_nameslist (serv, word[5],
								 (word_eol[6][0] == ':') ? word_eol[6] + 1 : word_eol[6],
								 tags_data);
		break;

	case 366:
		if (!inbound_nameslist_end (serv, word[4], tags_data))
			goto def;
		break;

	case 367: /* banlist entry */
		if (!inbound_banlist (sess, atol (word[7]), word[4], word[5], word[6], 367,
									 tags_data))
			goto def;
		break;

	case 368:
		sess = find_channel (serv, word[4]);
		if (!sess)
		{
			sess = serv->front_session;
			goto def;
		}
		if (!fe_ban_list_end (sess, 368))
			goto def;
		break;

	case 369:	/* WHOWAS end */
	case 406:	/* WHOWAS error */
		EMIT_SIGNAL_TIMESTAMP (XP_TE_SERVTEXT, whois_sess, text, word[1], word[2],
									  NULL, 0, tags_data->timestamp);
		serv->inside_whois = 0;
		break;

	case 372:	/* motd text */
	case 375:	/* motd start */
		if (!prefs.hex_irc_skip_motd || serv->motd_skipped)
			EMIT_SIGNAL_TIMESTAMP (XP_TE_MOTD, serv->server_session, text, NULL,
										  NULL, NULL, 0, tags_data->timestamp);
		break;

	case 376:	/* end of motd */
	case 422:	/* motd file is missing */
		inbound_login_end (sess, text, tags_data);
		break;

	case 432:	/* erroneous nickname */
		if (serv->end_of_motd)
		{
			goto def;
		}
		inbound_next_nick (sess,  word[4], 1, tags_data);
		break;

	case 433:	/* nickname in use */
		if (serv->end_of_motd)
		{
			goto def;
		}
		inbound_next_nick (sess,  word[4], 0, tags_data);
		break;

	case 437:
		if (serv->end_of_motd || is_channel (serv, word[4]))
			goto def;
		inbound_next_nick (sess, word[4], 0, tags_data);
		break;

	case 471:
		EMIT_SIGNAL_TIMESTAMP (XP_TE_USERLIMIT, sess, word[4], NULL, NULL, NULL, 0,
									  tags_data->timestamp);
		break;

	case 473:
		EMIT_SIGNAL_TIMESTAMP (XP_TE_INVITE, sess, word[4], NULL, NULL, NULL, 0,
									  tags_data->timestamp);
		break;

	case 474:
		EMIT_SIGNAL_TIMESTAMP (XP_TE_BANNED, sess, word[4], NULL, NULL, NULL, 0,
									  tags_data->timestamp);
		break;

	case 475:
		EMIT_SIGNAL_TIMESTAMP (XP_TE_KEYWORD, sess, word[4], NULL, NULL, NULL, 0,
									  tags_data->timestamp);
		break;

	case 601:
		notify_set_offline (serv, word[4], FALSE, tags_data);
		break;

	case 605:
		notify_set_offline (serv, word[4], TRUE, tags_data);
		break;

	case 600:
	case 604:
		notify_set_online (serv, word[4], tags_data);
		break;

	case 728:	/* +q-list entry */
		/* NOTE:  FREENODE returns these results inconsistent with e.g. +b */
		/* Who else has imlemented MODE_QUIET, I wonder? */
		if (!inbound_banlist (sess, atol (word[8]), word[4], word[6], word[7], 728,
									 tags_data))
			goto def;
		break;

	case 729:	/* end of quiet list */
		if (!fe_ban_list_end (sess, 729))
			goto def;
		break;

	case 730: /* RPL_MONONLINE */
		notify_set_online_list (serv, word[4] + 1, tags_data);
		break;

	case 731: /* RPL_MONOFFLINE */
		notify_set_offline_list (serv, word[4] + 1, FALSE, tags_data);
		break;

	case 900:	/* successful SASL 'logged in as ' */
		EMIT_SIGNAL_TIMESTAMP (XP_TE_SERVTEXT, serv->server_session, 
									  word_eol[6]+1, word[1], word[2], NULL, 0,
									  tags_data->timestamp);
		break;
	case 903:	/* successful SASL auth */
	case 904:	/* failed SASL auth */
		if (inbound_sasl_error (serv))
			break; /* might retry */
	case 905:	/* failed SASL auth */
	case 906:	/* aborted */
	case 907:	/* attempting to re-auth after a successful auth */
		EMIT_SIGNAL_TIMESTAMP (XP_TE_SASLRESPONSE, serv->server_session, word[1],
									  word[2], word[3], ++word_eol[4], 0,
									  tags_data->timestamp);
		if (!serv->sent_capend)
		{
			serv->sent_capend = TRUE;
			tcp_send_len (serv, "CAP END\r\n", 9);
		}
		break;

	default:

		if (serv->inside_whois && word[4][0])
		{
			/* some unknown WHOIS reply, ircd coders make them up weekly */
			if (!serv->skip_next_whois)
				EMIT_SIGNAL_TIMESTAMP (XP_TE_WHOIS_SPECIAL, whois_sess, word[4],
											  (word_eol[5][0] == ':') ? word_eol[5] + 1 : word_eol[5],
											  word[2], NULL, 0, tags_data->timestamp);
			return;
		}

	def:
		{
			session *sess;
		
			if (is_channel (serv, word[4]))
			{
				sess = find_channel (serv, word[4]);
				if (!sess)
					sess = serv->server_session;
			}
			else if ((sess=find_dialog (serv,word[4]))) /* user with an open dialog */
				;
			else
				sess=serv->server_session;
			
			EMIT_SIGNAL_TIMESTAMP (XP_TE_SERVTEXT, sess, text, word[1], word[2],
										  NULL, 0, tags_data->timestamp);
		}
	}
}

/* handle named messages that starts with a ':' */

static void
process_named_msg (session *sess, char *type, char *word[], char *word_eol[],
						 const message_tags_data *tags_data)
{
	server *serv = sess->server;
	char ip[128], nick[NICKLEN];
	char *text, *ex;
	int len = strlen (type);

	/* fill in the "ip" and "nick" buffers */
	ex = strchr (word[1], '!');
	if (!ex)							  /* no '!', must be a server message */
	{
		safe_strcpy (ip, word[1], sizeof (ip));
		safe_strcpy (nick, word[1], sizeof (nick));
	} else
	{
		safe_strcpy (ip, ex + 1, sizeof (ip));
		ex[0] = 0;
		safe_strcpy (nick, word[1], sizeof (nick));
		ex[0] = '!';
	}

	if (len == 4)
	{
		guint32 t;

		t = WORDL((guint8)type[0], (guint8)type[1], (guint8)type[2], (guint8)type[3]); 	
		/* this should compile to a bunch of: CMP.L, JE ... nice & fast */
		switch (t)
		{
		case WORDL('J','O','I','N'):
			{
				char *chan = word[3];
				char *account = word[4];
				char *realname = word_eol[5] + 1;

				if (*chan == ':')
					chan++;
				if (!serv->p_cmp (nick, serv->nick))
					inbound_ujoin (serv, chan, nick, ip, tags_data);
				else
					inbound_join (serv, chan, nick, ip, account, realname,
									  tags_data);
			}
			return;

		case WORDL('K','I','C','K'):
			{
				char *kicked = word[4];
				char *reason = word_eol[5];
				if (*kicked)
				{
					if (*reason == ':')
						reason++;
					if (!strcmp (kicked, serv->nick))
	 					inbound_ukick (serv, word[3], nick, reason, tags_data);
					else
						inbound_kick (serv, word[3], kicked, nick, reason, tags_data);
				}
			}
			return;

		case WORDL('K','I','L','L'):
			EMIT_SIGNAL_TIMESTAMP (XP_TE_KILL, sess, nick, word_eol[5], NULL, NULL,
										  0, tags_data->timestamp);
			return;

		case WORDL('M','O','D','E'):
			handle_mode (serv, word, word_eol, nick, FALSE, tags_data);	/* modes.c */
			return;

		case WORDL('N','I','C','K'):
			inbound_newnick (serv, nick, 
								  (word_eol[3][0] == ':') ? word_eol[3] + 1 : word_eol[3],
								  FALSE, tags_data);
			return;

		case WORDL('P','A','R','T'):
			{
				char *chan = word[3];
				char *reason = word_eol[4];

				if (*chan == ':')
					chan++;
				if (*reason == ':')
					reason++;
				if (!strcmp (nick, serv->nick))
					inbound_upart (serv, chan, ip, reason, tags_data);
				else
					inbound_part (serv, chan, nick, ip, reason, tags_data);
			}
			return;

		case WORDL('P','O','N','G'):
			inbound_ping_reply (serv->server_session,
									  (word[4][0] == ':') ? word[4] + 1 : word[4],
									  word[3], tags_data);
			return;

		case WORDL('Q','U','I','T'):
			inbound_quit (serv, nick, ip,
							  (word_eol[3][0] == ':') ? word_eol[3] + 1 : word_eol[3],
							  tags_data);
			return;

		case WORDL('A','W','A','Y'):
			inbound_away_notify (serv, nick,
										(word_eol[3][0] == ':') ? word_eol[3] + 1 : NULL,
										tags_data);
			return;
		}

		goto garbage;
	}

	else if (len >= 5)
	{
		guint32 t;

		t = WORDL((guint8)type[0], (guint8)type[1], (guint8)type[2], (guint8)type[3]); 	
		/* this should compile to a bunch of: CMP.L, JE ... nice & fast */
		switch (t)
		{

		case WORDL('A','C','C','O'):
			inbound_account (serv, nick, word[3], tags_data);
			return;
			
		case WORDL('I','N','V','I'):
			if (ignore_check (word[1], IG_INVI))
				return;
			
			if (word[4][0] == ':')
				EMIT_SIGNAL_TIMESTAMP (XP_TE_INVITED, sess, word[4] + 1, nick,
											  serv->servername, NULL, 0,
											  tags_data->timestamp);
			else
				EMIT_SIGNAL_TIMESTAMP (XP_TE_INVITED, sess, word[4], nick,
											  serv->servername, NULL, 0,
											  tags_data->timestamp);
				
			return;

		case WORDL('N','O','T','I'):
			{
				int id = FALSE;								/* identified */

				text = word_eol[4];
				if (*text == ':')
				{
					text++;
				}

#ifdef USE_OPENSSL
				if (!strncmp (text, "CHALLENGE ", 10))		/* QuakeNet CHALLENGE upon our request */
				{
					char *response = challengeauth_response (((ircnet *)serv->network)->user ? ((ircnet *)serv->network)->user : prefs.hex_irc_user_name, serv->password, word[5]);

					tcp_sendf (serv, "PRIVMSG %s :CHALLENGEAUTH %s %s %s\r\n",
						CHALLENGEAUTH_NICK,
						((ircnet *)serv->network)->user ? ((ircnet *)serv->network)->user : prefs.hex_irc_user_name,
						response,
						CHALLENGEAUTH_ALGO);

					g_free (response);
					return;									/* omit the CHALLENGE <hash> ALGOS message */
				}
#endif

				if (serv->have_idmsg)
				{
					if (*text == '+')
					{
						id = TRUE;
						text++;
					} else if (*text == '-')
						text++;
				}

				if (!ignore_check (word[1], IG_NOTI))
					inbound_notice (serv, word[3], nick, text, ip, id, tags_data);
			}
			return;

		case WORDL('P','R','I','V'):
			{
				char *to = word[3];
				int len;
				int id = FALSE;	/* identified */
				if (*to)
				{
					/* Handle limited channel messages, for now no special event */
					if (strchr (serv->chantypes, to[0]) == NULL
						&& strchr (serv->nick_prefixes, to[0]) != NULL)
						to++;
						
					text = word_eol[4];
					if (*text == ':')
						text++;
					if (serv->have_idmsg)
					{
						if (*text == '+')
						{
							id = TRUE;
							text++;
						} else if (*text == '-')
							text++;
					}
					len = strlen (text);
					if (text[0] == 1 && text[len - 1] == 1)	/* ctcp */
					{
						text[len - 1] = 0;
						text++;
						if (g_ascii_strncasecmp (text, "ACTION", 6) != 0)
							flood_check (nick, ip, serv, sess, 0);
						if (g_ascii_strncasecmp (text, "DCC ", 4) == 0)
							/* redo this with handle_quotes TRUE */
							process_data_init (word[1], word_eol[1], word, word_eol, TRUE, FALSE);
						ctcp_handle (sess, to, nick, ip, text, word, word_eol, id,
										 tags_data);
					} else
					{
						if (is_channel (serv, to))
						{
							if (ignore_check (word[1], IG_CHAN))
								return;
							inbound_chanmsg (serv, NULL, to, nick, text, FALSE, id,
												  tags_data);
						} else
						{
							if (ignore_check (word[1], IG_PRIV))
								return;
							inbound_privmsg (serv, nick, ip, text, id, tags_data);
						}
					}
				}
			}
			return;

		case WORDL('T','O','P','I'):
			inbound_topicnew (serv, nick, word[3],
									(word_eol[4][0] == ':') ? word_eol[4] + 1 : word_eol[4],
									tags_data);
			return;

		case WORDL('W','A','L','L'):
			text = word_eol[3];
			if (*text == ':')
				text++;
			EMIT_SIGNAL_TIMESTAMP (XP_TE_WALLOPS, sess, nick, text, NULL, NULL, 0,
										  tags_data->timestamp);
			return;
		}
	}

	else if (len == 3)
	{
		guint32 t;

		t = WORDL((guint8)type[0], (guint8)type[1], (guint8)type[2], (guint8)type[3]);
		switch (t)
		{
			case WORDL('C','A','P','\0'):
				if (strncasecmp (word[4], "ACK", 3) == 0)
				{
					inbound_cap_ack (serv, word[1], 
										  word[5][0] == ':' ? word_eol[5] + 1 : word_eol[5],
										  tags_data);
				}
				else if (strncasecmp (word[4], "LS", 2) == 0)
				{
					inbound_cap_ls (serv, word[1], 
										 word[5][0] == ':' ? word_eol[5] + 1 : word_eol[5],
										 tags_data);
				}
				else if (strncasecmp (word[4], "NAK", 3) == 0)
				{
					inbound_cap_nak (serv, tags_data);
				}
				else if (strncasecmp (word[4], "LIST", 4) == 0)	
				{
					inbound_cap_list (serv, word[1], 
											word[5][0] == ':' ? word_eol[5] + 1 : word_eol[5],
											tags_data);
				}

				return;
		}
	}

garbage:
	/* unknown message */
	PrintTextTimeStampf (sess, tags_data->timestamp, "GARBAGE: %s\n", word_eol[1]);
}

/* handle named messages that DON'T start with a ':' */

static void
process_named_servermsg (session *sess, char *buf, char *rawname, char *word_eol[],
								 const message_tags_data *tags_data)
{
	sess = sess->server->server_session;

	if (!strncmp (buf, "PING ", 5))
	{
		tcp_sendf (sess->server, "PONG %s\r\n", buf + 5);
		return;
	}
	if (!strncmp (buf, "ERROR", 5))
	{
		EMIT_SIGNAL_TIMESTAMP (XP_TE_SERVERERROR, sess, buf + 7, NULL, NULL, NULL,
									  0, tags_data->timestamp);
		return;
	}
	if (!strncmp (buf, "NOTICE ", 7))
	{
		buf = word_eol[3];
		if (*buf == ':')
			buf++;
		EMIT_SIGNAL_TIMESTAMP (XP_TE_SERVNOTICE, sess, buf, 
									  sess->server->servername, NULL, NULL, 0,
									  tags_data->timestamp);
		return;
	}
	if (!strncmp (buf, "AUTHENTICATE", 12))
	{
		inbound_sasl_authenticate (sess->server, word_eol[2]);
		return;
	}

	EMIT_SIGNAL_TIMESTAMP (XP_TE_SERVTEXT, sess, buf, sess->server->servername,
								  rawname, NULL, 0, tags_data->timestamp);
}

/* Returns the timezone offset. This should be the same as the variable
 * "timezone" in time.h, but *BSD doesn't have it.
 */
static int
get_timezone(void)
{
	struct tm tm_utc, tm_local;
	time_t t, time_utc, time_local;

	time (&t);

	/* gmtime() and localtime() are thread-safe on windows.
	 * on other systems we should use {gmtime,localtime}_r().
	 */
#if WIN32
	tm_utc = *gmtime (&t);
	tm_local = *localtime (&t);
#else
	gmtime_r (&t, &tm_utc);
	localtime_r (&t, &tm_local);
#endif

	time_utc = mktime (&tm_utc);
	time_local = mktime (&tm_local);

	return time_utc - time_local;
}

/* Handle time-server tags.
 * 
 * Sets tags_data->timestamp to the correct time (in unix time). 
 * This received time is always in UTC.
 *
 * See http://ircv3.atheme.org/extensions/server-time-3.2
 */
static void
handle_message_tag_time (const char *time, message_tags_data *tags_data)
{
	/* The time format defined in the ircv3.2 specification is
	 *       YYYY-MM-DDThh:mm:ss.sssZ
	 * but znc simply sends a unix time (with 3 decimal places for miliseconds)
	 * so we might as well support both.
	 */
	if (!*time)
		return;
	
	if (time[strlen (time) - 1] == 'Z')
	{
		/* as defined in the specification */
		struct tm t;
		int z;

		/* we ignore the milisecond part */
		z = sscanf (time, "%d-%d-%dT%d:%d:%d", &t.tm_year, &t.tm_mon, &t.tm_mday,
					&t.tm_hour, &t.tm_min, &t.tm_sec);

		if (z != 6)
			return;

		t.tm_year -= 1900;
		t.tm_mon -= 1;
		t.tm_isdst = 0; /* day light saving time */

		tags_data->timestamp = mktime (&t);

		if (tags_data->timestamp < 0)
		{
			tags_data->timestamp = 0;
			return;
		}

		/* get rid of the local time (mktime() receives a local calendar time) */
		tags_data->timestamp -= get_timezone();
	}
	else
	{
		/* znc */
		long long int t;

		/* we ignore the milisecond part */
		if (sscanf (time, "%lld", &t) != 1)
			return;

		tags_data->timestamp = (time_t) t;
	}
}

/* Handle message tags.
 *
 * See http://ircv3.atheme.org/specification/message-tags-3.2 
 */
static void
handle_message_tags (server *serv, const char *tags_str,
							message_tags_data *tags_data)
{
	char **tags;
	int i;

	/* FIXME We might want to avoid the allocation overhead here since 
	 * this might be called for every message from the server.
	 */
	tags = g_strsplit (tags_str, ";", 0);

	for (i=0; tags[i]; i++)
	{
		char *key = tags[i];
		char *value = strchr (tags[i], '=');

		if (!value)
			continue;

		*value = '\0';
		value++;

		if (serv->have_server_time && !strcmp (key, "time"))
			handle_message_tag_time (value, tags_data);
	}
	
	g_strfreev (tags);
}

/* irc_inline() - 1 single line received from serv */
static void
irc_inline (server *serv, char *buf, int len)
{
	session *sess, *tmp;
	char *type, *text;
	char *word[PDIWORDS+1];
	char *word_eol[PDIWORDS+1];
	char pdibuf_static[522]; /* 1 line can potentially be 512*6 in utf8 */
	char *pdibuf = pdibuf_static;
	message_tags_data tags_data = MESSAGE_TAGS_DATA_INIT;

	/* need more than 522? fall back to malloc */
	if (len >= sizeof (pdibuf_static))
		pdibuf = malloc (len + 1);

	sess = serv->front_session;

	/* Python relies on this */
	word[PDIWORDS] = NULL;
	word_eol[PDIWORDS] = NULL;

	if (*buf == '@')
	{
		char *tags = buf + 1; /* skip the '@' */
		char *sep = strchr (buf, ' ');

		if (!sep)
			goto xit;
		
		*sep = '\0';
		buf = sep + 1;

		handle_message_tags(serv, tags, &tags_data);
	}

	url_check_line (buf, len);

	/* split line into words and words_to_end_of_line */
	process_data_init (pdibuf, buf, word, word_eol, FALSE, FALSE);

	if (buf[0] == ':')
	{
		int eat1;
		int eat2;

		/* find a context for this message */
		if (is_channel (serv, word[3]))
		{
			tmp = find_channel (serv, word[3]);
			if (tmp)
				sess = tmp;
		}

		/* for server messages, the 2nd word is the "message type" */
		type = word[2];

		word[0] = type;
		word_eol[1] = buf;	/* keep the ":" for plugins */

		eat1 = plugin_emit_server (sess, type, word, word_eol);
		eat2 = plugin_emit_server_attrs (sess, type, word, word_eol, 
										 tags_data.timestamp);

		if (eat1 || eat2)
			goto xit;

		word[1]++;
		word_eol[1] = buf + 1;	/* but not for HexChat internally */

	} else
	{
		int eat1;
		int eat2;

		word[0] = type = word[1];

		eat1 = plugin_emit_server (sess, type, word, word_eol);
		eat2 = plugin_emit_server_attrs (sess, type, word, word_eol,
										 tags_data.timestamp);

		if (eat1 || eat2)
			goto xit;
	}

	if (buf[0] != ':')
	{
		process_named_servermsg (sess, buf, word[0], word_eol, &tags_data);
		goto xit;
	}

	/* see if the second word is a numeric */
	if (isdigit ((unsigned char) word[2][0]))
	{
		text = word_eol[4];
		if (*text == ':')
			text++;

		process_numeric (sess, atoi (word[2]), word, word_eol, text, &tags_data);
	} else
	{
		process_named_msg (sess, type, word, word_eol, &tags_data);
	}

xit:
	if (pdibuf != pdibuf_static)
		free (pdibuf);
}

void
proto_fill_her_up (server *serv)
{
	serv->p_inline = irc_inline;
	serv->p_invite = irc_invite;
	serv->p_cycle = irc_cycle;
	serv->p_ctcp = irc_ctcp;
	serv->p_nctcp = irc_nctcp;
	serv->p_quit = irc_quit;
	serv->p_kick = irc_kick;
	serv->p_part = irc_part;
	serv->p_ns_identify = irc_ns_identify;
	serv->p_ns_ghost = irc_ns_ghost;
	serv->p_join = irc_join;
	serv->p_join_list = irc_join_list;
	serv->p_login = irc_login;
	serv->p_join_info = irc_join_info;
	serv->p_mode = irc_mode;
	serv->p_user_list = irc_user_list;
	serv->p_away_status = irc_away_status;
	/*serv->p_get_ip = irc_get_ip;*/
	serv->p_whois = irc_user_whois;
	serv->p_get_ip = irc_user_list;
	serv->p_get_ip_uh = irc_userhost;
	serv->p_set_back = irc_set_back;
	serv->p_set_away = irc_set_away;
	serv->p_message = irc_message;
	serv->p_action = irc_action;
	serv->p_notice = irc_notice;
	serv->p_topic = irc_topic;
	serv->p_list_channels = irc_list_channels;
	serv->p_change_nick = irc_change_nick;
	serv->p_names = irc_names;
	serv->p_ping = irc_ping;
	serv->p_raw = irc_raw;
	serv->p_cmp = rfc_casecmp;	/* can be changed by 005 in modes.c */
}