Initial commit

This commit is contained in:
2026-08-31 21:04:48 +03:00
commit c0d5110ea7
347 changed files with 57952 additions and 0 deletions
+6
View File
@@ -0,0 +1,6 @@
GET /index.php HTTP/1.0
Host: zxart.ee
User-Agent: ZiFi (ZX Evo)
Accept: */*
Connection: close
+51
View File
@@ -0,0 +1,51 @@
http://bbs.espressif.com/
"[Latest Release] ESP8266 SDK"
"Non-OS SDK..." - отгрузочная прошивка
SDK Development Guide @ http://bbs.espressif.com/viewtopic.php?f=51&t=1024
AT Commands User Guide @ http://bbs.espressif.com/viewtopic.php?f=51&t=1022
All documentations @ http://bbs.espressif.com/viewforum.php?f=51
http://esp8266.ru/
http://geektimes.ru/post/241054/
espprob1.a80 http://tslabs.info/forum/viewtopic.php?p=17447#p17447
~~~~~~~~~~~~
видео: https://yadi.sk/i/afXhFTDpijb63
голубой - коментарии
жёлтый - посылаемые модулю команды
белый - ответы модуля (байты после +IPD,xxxx: не отображаются)
ATE0
проверка связи, отключение "эха"
AT+CWMODE_DEF=1
режим "станция"
AT+CWAUTOCONN=0
откл. автоподключение к точке доступа (AP)
AT+CWQAP
отключение от AP (если уже было подключение)
AT+CWLAP
список доступных AP
AT+CWJAP="имя_точки","пароль"
подключение к AP
далее пинг и собственно HTTP запросы
Binary file not shown.
Binary file not shown.
Binary file not shown.
+48
View File
@@ -0,0 +1,48 @@
AT
OK
AT+GMR
AT version:0.60.0.0(Jan 29 2016 15:10:17)
SDK version:1.5.2(80914727)
compile time:Jan 29 2016 19:06:50
OK
AT+CWMODE_DEF? busy p...
+CWMODE_DEF:1
OK
AT+CWLAP busy p...
+CWLAP:(3,"win",-77,"08:60:6e:24:89:70",13,85,0)
+CWLAP:(4,"YV",-38,"08:60:6e:d2:f7:58",13,86,0)
OK
AT+CWJAP_CUR="YV","1234123412" WIFI CONNECTED
WIFI GOT IP
OK
AT+CIPSTA? +CIPSTA:ip:"192.168.1.248"
+CIPSTA:gateway:"192.168.1.1"
+CIPSTA:netmask:"255.255.255.0"
OK
AT+PING="google.com" +24
OK
AT+CIPSTART="TCP","zxart.ee",80 busy p...
CONNECT
OK
AT+CIPSEND=4
OK
>
Recv 4 bytes
SEND OK
AT+CIPSEND=104
GET /index.php HTTP/1.0
Host: zxart.ee
User-Agent: ZiFi (ZX Evo)
Accept: */*
Connection: close
+706
View File
@@ -0,0 +1,706 @@
relaxed on
cpu z80undoc
bigbuff:equ 0x8000
org 0x6000
;---------------------------------------
res 4,(iy+1)
ld bc,0x7ffd
ld a,0x17
out (c),a
ld a,0x07
ld (0x5c48),a
ld (0x5c8d),a
xor a
out (0xfe),a
call zx_cls
ld hl,udg
ld (0x5c7b),hl
p100: ld a,0x45
ld (0x5c8f),a
ld hl,p100
push hl
ld hl,msg_baudmenu
call zx_puts_safe
p102: call zx_getkey
ld de,1
cp 0x31
jr z,p101
inc e
cp 0x32
jr z,p101
inc e
cp 0x33
jr z,p101
inc e
cp 0x34
jr z,p101
ld e,6
cp 0x35
jr z,p101
ld e,8
cp 0x36
jr z,p101
ld e,12
cp 0x37
jr nz,p102
p101:
call rs232_init
halt
ld b,3
p103: push bc
ld de,25
ld hl,cmd_ate0
call send_cmd_wait_ok
pop bc
jr z,p104
djnz p103
jp x_err
p104:
;
ld hl,msg_req_vers
call zx_puts_safe
ld de,25
ld hl,cmd_gmr
call send_cmd_wait_ok
jp nz,x_err
;
ld hl,msg_press_key
call zx_puts_safe
call zx_getkey
;
ld hl,msg_chg_baud
call zx_puts_safe
ld de,25
ld hl,cmd_uart_9600
call send_cmd_wait_ok
jp nz,x_err
ld de,12
call rs232_init
halt
;
ld de,25
ld hl,cmd_cwmode
call send_cmd_wait_ok
jp nz,x_err
ld de,25
ld hl,cmd_cwautoconn
call send_cmd_wait_ok
jp nz,x_err
ld de,25
ld hl,cmd_cwqap
call send_cmd_wait_ok
jp nz,x_err
;
p110: ld hl,msg_ap_list
call zx_puts_safe
ld de,250
ld hl,cmd_cwlap
call send_cmd_wait_ok
jp nz,x_err
ld hl,msg_repeat
call zx_puts_safe
call zx_getkey
cp 'R'
jr z,p110
cp 'r'
jr z,p110
;
ld hl,msg_ap_conn
call zx_puts_safe
ld de,1000
ld hl,cmd_cwjap
call send_cmd_wait_ok
jp z,p120
call x_err
jr p110
;
p120: ld hl,msg_ipcfg
call zx_puts_safe
ld de,25
ld hl,cmd_cipsta
call send_cmd_wait_ok
call nz,x_err
;
ld hl,msg_ping
call zx_puts_safe
ld de,75
ld hl,cmd_ping_g
call send_cmd_wait_ok
call nz,x_err
ld de,75
ld hl,cmd_ping_y
call send_cmd_wait_ok
call nz,x_err
;
p199: ld hl,msg_press_key
call zx_puts_safe
call zx_getkey
;
p200: ld hl,bigbuff
ld (ptr),hl
ld de,bigbuff+1
ld bc,16384
ld (hl),0
ldir
call zx_cls
ld a,0x45
ld (0x5c8f),a
ld hl,msg_menuload
call zx_puts_safe
p201: call zx_getkey
cp 0x31
jr c,p201
cp 0x3a
jr nc,p201
sub 0x31
ld (resnum),a
call rs232_reset_fifo
ld hl,msg_open_tcp
call zx_puts_safe
ld de,250
ld hl,cmd_conn2site
call send_cmd_wait_ok
jp z,p210
call x_err
jr p199
p210:
ld de,50
call set_timeout50
ld a,0x06
ld (0x5c8f),a
ld hl,cmd_cipsend
call rs232_putstr
ld a,(resnum)
ld l,a
ld h,0
add hl,hl
add hl,hl
ld de,tabl_ptrurl
add hl,de
ld e,(hl)
inc hl
ld d,(hl)
ex de,hl
call rs232_putstr
ld hl,str_crlf
call rs232_putstr
call wait_ok
jp z,p211
call x_err
jp p199
p211: ld a,0x07
ld (0x5c8f),a
p212: call rs232_getchar
jr z,p212
push af
call zx_putchar_safe
pop af
cp '>'
jr nz,p211
ld a,0x06
ld (0x5c8f),a
ld hl,str_get1
call rs232_putstr
ld a,(resnum)
ld l,a
ld h,0
add hl,hl
inc hl
add hl,hl
ld de,tabl_ptrurl
add hl,de
ld e,(hl)
inc hl
ld d,(hl)
ex de,hl
call rs232_putstr
ld hl,str_get2
call rs232_putstr
call wait_ok
cp 0xfd
jp z,p220
call x_err
jp p199
p220: ld de,1000
call set_timeout50
p22a: ld a,0x07
ld (0x5c8f),a
ld hl,strbuff
ld (hl),0
call rdipd
ld a,(strbuff)
or a
jr nz,p221
call x_tout
jp p199
p221: ld de,str_ipd
call ss_cmp
jr z,p222
call x_err
jp p199
p222:
ld a,0x45
ld (0x5c8f),a
ld hl,msg_skip
call zx_puts_safe
ld hl,0
ld de,strbuff+7
p223: ld a,(de)
inc de
cp ':'
jr z,p230
sub 0x30
ld c,l
ld b,h
add hl,hl
add hl,hl
add hl,bc
add hl,hl
ld c,a
ld b,0
add hl,bc
jr p223
p230: ld (packsz),hl
ex de,hl
ld hl,(ptr)
p231: call rs232_getchar
jr nz,p232
call check_timeout
jr c,p231
call x_tout
jp p199
p232: ld (hl),a
inc hl
dec de
ld a,d
or e
jr nz,p231
ld (ptr),hl
ld hl,(packsz)
ld de,1360
xor a
sbc hl,de
jr nc,p22a
;
ld hl,bigbuff
p241: ld a,(hl)
inc hl
p242: cp 10
jr nz,p241
ld a,(hl)
inc hl
cp 13
jr nz,p242
inc hl
ld a,(resnum)
cp 3
jp c,pscr0
cp 6
jp c,pgiga0
;pmus0:
push hl
ex de,hl
ld hl,(ptr)
xor a
sbc hl,de
ld c,l
ld b,h
pop hl
ld de,0xc86e
ldir
ld hl,vtpl
ld de,0xc000
ld bc,sz_vtpl
ldir
ld a,0x45
ld (0x5c8f),a
ld hl,msg_musply
call zx_puts_safe
call 0xc000
ei
res 5,(iy+1)
pmus1: halt
call 0xc005
bit 5,(iy+1)
jr z,pmus1
call 0xc008
jp p200
;
pgiga0: ld de,0x4000
ld bc,0x1b00
ldir
ld de,0xc000
ld bc,0x1b00
ldir
res 5,(iy+1)
ld bc,0x7ffd
pgiga1: halt
ld a,0x1f
out (c),a
halt
ld a,0x17
out (c),a
bit 5,(iy+1)
jr z,pgiga1
jp p200
;
pscr0: ld de,0x4000
ld bc,0x1b00
ldir
call zx_getkey
jp p200
;------------------------------
x_err: ld hl,msgff_error
cp 1
jr nz,x_er1
x_tout: ld hl,msgff_timeout
x_er1: call zx_puts_ff
ret
;------------------------------
send_cmd_wait_ok:
push hl
call set_timeout50
call rs232_reset_fifo
ld a,0x06
ld (0x5c8f),a
pop hl
call rs232_putstr
ld a,0x45
ld (0x5c8f),a
wait_ok:ld hl,strbuff
call rdstr
ld a,(strbuff)
or a
jr nz,_scwo1
inc a
ret
_scwo1: ld a,0x07
ld (0x5c8f),a
ld hl,strbuff
call zx_puts_safe
ld a,0x45
ld (0x5c8f),a
ld de,str_ok
call ss_cmp
ld a,0x00
jr z,_scwo9
ld de,str_fail
call ss_cmp
ld a,0xff
jr z,_scwo9
ld de,str_error
call ss_cmp
ld a,0xfe
jr z,_scwo9
ld de,str_send_ok
call ss_cmp
ld a,0xfd
jr nz,wait_ok
_scwo9: or a
ret
;------------------------------
rdstr: call rs232_getchar
jr z,rdst2
cp 10 ;LF
jr z,rdst3
ld (hl),a
inc hl
jr rdstr
rdst2: call check_timeout
jr c,rdstr
rdst3: ld (hl),0
ret
;------------------------------
rdipd: call rs232_getchar
jr z,ripd2
ld (hl),a
inc hl
push af
call zx_putchar_safe
pop af
cp ':'
ret z
jr rdipd
ripd2: call check_timeout
jr c,rdipd
ret
;------------------------------
ss_cmp: ld hl,strbuff
ss_cm1: ld a,(de)
or a
ret z
inc de
cpi
jr z,ss_cm1
ret
;------------------------------
rs232_init:
ld bc,0xfbef ;LCR
ld a,0x83
out (c),a
ld b,0xf8 ;DLL
out (c),e
inc b ;DLM
out (c),d
ld b,0xfc ;MCR
ld a,0x03
out (c),a
dec b ;LCR
ld a,0x03
out (c),a
rs232_reset_fifo:
ld bc,0xfaef ;FCR
ld a,0x07 ;FIFO reset
out (c),a
ld a,0x01
out (c),A
_clfifo:ld b,0xfd ;LSR
in a,(c)
and 0x01
ret z
ld b,0xf8 ;DAT
in a,(c)
jr _clfifo
;------------------------------
rs232_putchar:
push AF
call zx_putchar_safe
pop de
ld bc,0xfdef ;LSR
_putch1:in a,(c)
and 0x20
jr z,_putch1
ld b,0xf8 ;DAT
out (c),d
ret
;------------------------------
rs232_putstr:
ld a,(hl)
inc hl
or a
ret z
call rs232_putchar
jr rs232_putstr
;------------------------------
rs232_getchar:
ld bc,0xfdef ;LSR
in a,(c)
and 0x01
ret z
ld b,0xf8 ;DAT
in a,(c)
inc b
ret
;------------------------------
zx_putchar_safe:
cp 10 ;LF
ret z
cp 13 ;CR
jr z,_putc1
cp 0x20
jr c,_putc2
cp 0x80
jr c,_putc1
_putc2: ld a,0x90
_putc1: push hl
rst 0x10
pop hl
ret
;------------------------------
zx_puts_safe:
ld a,0xff
ld (0x5c8c),a
_puts1: ld a,(hl)
inc hl
or a
ret z
call zx_putchar_safe
jr _puts1
;------------------------------
zx_puts_ff:
ld a,0xff
ld (0x5c8c),a
_psff1: ld a,(hl)
inc hl
cp 0xff
ret z
push hl
rst 0x10
pop hl
jr _psff1
;------------------------------
zx_getkey:
res 5,(iy+1)
_getk1: bit 5,(iy+1)
jr z,_getk1
ld a,(iy-50)
ret
;------------------------------
zx_cls: ld a,2
ld (0x5c6b),a
call 0x0d6b
ld a,2
call 0x1601
xor a
ld (0x5c6b),a
ret
;------------------------------
set_timeout50:
ld hl,(0x5c78)
add hl,de
ld (tmout),hl
ret
;------------------------------
check_timeout:
push hl
push de
ld de,(tmout)
ld hl,(0x5c78)
xor a
sbc hl,de
pop de
pop hl
ret
;------------------------------
tmout: defw 0
ptr: defw 0
packsz: defw 0
resnum: defb 0
;------------------------------
udg: defb 0b00000000
defb 0b01010100
defb 0b00101010
defb 0b01010100
defb 0b00101010
defb 0b01010100
defb 0b00101010
defb 0b00000000
;------------------------------
vtpl:
listing off
include "vtplayer.inc"
listing on
sz_vtpl:equ $-vtpl
;------------------------------
tabl_ptrurl:
defw str_rqsz1,str_uri1
defw str_rqsz2,str_uri2
defw str_rqsz3,str_uri3
defw str_rqsz4,str_uri4
defw str_rqsz5,str_uri5
defw str_rqsz6,str_uri6
defw str_rqsz7,str_uri7
defw str_rqsz8,str_uri8
defw str_rqsz9,str_uri9
;------------------------------
msgff_timeout: defb 19,1,13,16,2,"- Timeout! -",16,5,13,0xff
msgff_error: defb 19,1,13,16,2,"- Error! -",16,5,13,0xff
msg_baudmenu: defb "Select baudrate:",13
defb "1.115200",13
defb "2. 57600",13
defb "3. 38400",13
defb "4. 28800",13
defb "5. 19200",13
defb "6. 14400",13
defb "7. 9600",13,0
msg_req_vers: defb "Firmware version...",13,0
msg_press_key: defb "Press a key",13,0
msg_chg_baud: defb "Change baudrate...",13,0
msg_ap_list: defb "AccessPoint list...",13,0
msg_repeat: defb "R - repeat, else continue",13,0
msg_ap_conn: defb "Connect to AccessPoint...",13,0
msg_ipcfg: defb "IP config info...",13,0
msg_ping: defb "Ping...",13,0
msg_menuload: defb "Now, we can try to load some",13
defb "pre-defined resources",13
defb "from the Internet.",13
defb "1. scr #1",13
defb "2. scr #2",13
defb "3. scr #3",13
defb "4. gigascr #1",13
defb "5. gigascr #2",13
defb "6. gigascr #3",13
defb "7. pt3 #1",13
defb "8. pt3 #2",13
defb "9. pt3 #3",13,0
msg_open_tcp: defb "Open TCP connection...",13,0
msg_musply: defb 13,"PT3-module playing"
msg_skip: defb "...",0
cmd_ate0: defb "ATE0"
str_crlf: defb 13,10,0
cmd_gmr: defb "AT+GMR",13,10,0
cmd_uart_9600: defb "AT+UART_CUR=9600,8,1,0,0",13,10,0
cmd_cwmode: defb "AT+CWMODE_DEF=1",13,10,0
cmd_cwautoconn: defb "AT+CWAUTOCONN=0",13,10,0
cmd_cwqap: defb "AT+CWQAP",13,10,0
cmd_cwlap: defb "AT+CWLAP",13,10,0
cmd_cwjap: defb "AT+CWJAP_CUR=",0x22
defb "wifitest123" ; SSID
defb 0x22,0x2c,0x22
defb "ZXSpectrumForeverHelloEverybody321" ; password
defb 0x22,13,10,0
cmd_cipsta: defb "AT+CIPSTA?",13,10,0
cmd_ping_g: defb "AT+PING=",0x22,"google.com",0x22,13,10,0
cmd_ping_y: defb "AT+PING=",0x22,"yandex.ru",0x22,13,10,0
cmd_conn2site: defb "AT+CIPSTART=",0x22,"TCP",0x22,",",0x22
defb "zxart.ee" ; site
defb 0x22,",80",13,10,0
cmd_cipsend: defb "AT+CIPSEND=",0
str_get1: defb "GET ",0 ;size=4
str_get2: defb " HTTP/1.1",13,10 ;size=123
defb "Host: zxart.ee",13,10
defb "User-Agent: ESP8266-probe1 (ZX Spectrum; CPU Z80; RAM 128Kb)",13,10 ; show off ;)
defb "Accept: */*",13,10
defb "Connection: close",13,10,13,10,0
str_uri1: defb "/file/id:61049/filename:%D0%9A%D0%90%D0%A1%D0%B8%D0%BA_-_Banka_%282015%29_%283BM_OpenAir_2015%2C_3%29.scr",0 ;size=105
str_rqsz1: defb "232",0 ;232=4+105+123=get1+uri1+get2
str_uri2: defb "/file/id:61053/filename:Buddy_-_Drunk_Kung-Fu_%282015%29_%283BM_OpenAir_2015%2C_5%29.scr",0 ;size=88
str_rqsz2: defb "215",0 ;215=4+88+123=get1+uri2+get2
str_uri3: defb "/file/id:61058/filename:brightentayle_-_The_Split_Foundations_%282015%29_%283BM_OpenAir_2015%2C_6%29.scr",0 ;size=104
str_rqsz3: defb "231",0 ;231=4+104+123=get1+uri3+get2
str_uri4: defb "/file/id:61060/filename:Tutty_-_Bat2Con_%282015%29_%283BM_OpenAir_2015%2C_1%29.img",0 ;size=82
str_rqsz4: defb "209",0 ;209=4+82+123=get1+uri4+get2
str_uri5: defb "/file/id:61059/filename:Dimidrol_-_Amur_tiger_%282015%29_%283BM_OpenAir_2015%2C_2%29.img",0 ;size=88
str_rqsz5: defb "215",0 ;215=4+88+123=get1+uri5+get2
str_uri6: defb "/file/id:61061/filename:prof4d_-_Fructus_%282015%29_%283BM_OpenAir_2015%2C_4%29.img",0 ;size=83
str_rqsz6: defb "210",0 ;210=4+83+123=get1+uri6+get2
str_uri7: defb "/file/id:61065/filename:luchibobra_-_three_bad_mice_%282015%29_%283BM_OpenAir_2015%2C_1%29.pt3",0 ;size=94
str_rqsz7: defb "221",0 ;221=4+94+123=get1+uri7+get2
str_uri8: defb "/file/id:61067/filename:MmcM_-_summertime_%282015%29_%283BM_OpenAir_2015%2C_2%29.pt3",0 ;size=84
str_rqsz8: defb "211",0 ;211=4+84+123=get1+uri8+get2
str_uri9: defb "/file/id:61066/filename:wbc_-_isglass-3_%282015%29_%283BM_OpenAir_2015%2C_3%29.pt3",0 ;size=82
str_rqsz9: defb "209",0 ;209=4+82+123=get1+uri9+get2
str_ok: defb "OK",13,0
str_error: defb "ERROR",13,0
str_fail: defb "FAIL",13,0
str_send_ok: defb "SEND OK",13,0
str_ipd: defb 13,10,"+IPD,",0
strbuff:
;------------------------------
+94
View File
@@ -0,0 +1,94 @@
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <netdb.h>
int conn;
char sbuf[512];
void raw(char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
vsnprintf(sbuf, 512, fmt, ap);
va_end(ap);
printf("<< %s", sbuf);
write(conn, sbuf, strlen(sbuf));
}
int main() {
char *nick = "test";
char *channel = NULL;
char *host = "irc.dav7.net";
char *port = "6667";
char *user, *command, *where, *message, *sep, *target;
int i, j, l, sl, o = -1, start, wordcount;
char buf[513];
struct addrinfo hints, *res;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
getaddrinfo(host, port, &hints, &res);
conn = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
connect(conn, res->ai_addr, res->ai_addrlen);
raw("USER %s 0 0 :%s\r\n", nick, nick);
raw("NICK %s\r\n", nick);
while ((sl = read(conn, sbuf, 512))) {
for (i = 0; i < sl; i++) {
o++;
buf[o] = sbuf[i];
if ((i > 0 && sbuf[i] == '\n' && sbuf[i - 1] == '\r') || o == 512) {
buf[o + 1] = '\0';
l = o;
o = -1;
printf(">> %s", buf);
if (!strncmp(buf, "PING", 4)) {
buf[1] = 'O';
raw(buf);
} else if (buf[0] == ':') {
wordcount = 0;
user = command = where = message = NULL;
for (j = 1; j < l; j++) {
if (buf[j] == ' ') {
buf[j] = '\0';
wordcount++;
switch(wordcount) {
case 1: user = buf + 1; break;
case 2: command = buf + start; break;
case 3: where = buf + start; break;
}
if (j == l - 1) continue;
start = j + 1;
} else if (buf[j] == ':' && wordcount == 3) {
if (j < l - 1) message = buf + j + 1;
break;
}
}
if (wordcount < 2) continue;
if (!strncmp(command, "001", 3) && channel != NULL) {
raw("JOIN %s\r\n", channel);
} else if (!strncmp(command, "PRIVMSG", 7) || !strncmp(command, "NOTICE", 6)) {
if (where == NULL || message == NULL) continue;
if ((sep = strchr(user, '!')) != NULL) user[sep - user] = '\0';
if (where[0] == '#' || where[0] == '&' || where[0] == '+' || where[0] == '!') target = where; else target = user;
printf("[from: %s] [reply-with: %s] [where: %s] [reply-to: %s] %s", user, command, where, target, message);
//raw("%s %s :%s", command, target, message); // If you enable this the IRCd will get its "*** Looking up your hostname..." messages thrown back at it but it works...
}
}
}
}
}
return 0;
}
Binary file not shown.
+646
View File
@@ -0,0 +1,646 @@
/*% cc -g -Wall -lncurses -o # %
*/
#include <assert.h>
#include <limits.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include <curses.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <netdb.h>
#include <locale.h>
#define SCROLL 15
#define INDENT 21
#define DATEFMT "%H:%M"
#define PFMT "%-12s < %s"
#define SRV "irc.oftc.net"
#define PORT 6667
enum { ChanLen = 64, LineLen = 512, MaxChans = 16, BufSz = 2048, LogSz = 4096 };
char nick[64];
int quit, winchg;
int sfd; /* Server file descriptor. */
struct {
int x;
int y;
WINDOW *sw, *mw, *iw;
} scr; /* Screen relative data. */
struct Chan {
char name[ChanLen];
char *buf, *eol;
int n; /* Scroll offset. */
size_t sz; /* size of buf. */
} chl[MaxChans];
int nch, ch; /* Current number of channels, and current channel. */
char outb[BufSz], *outp=outb; /* Output buffer. */
static void scmd(char *, char *, char *, char *);
static void tdrawbar(void);
static void tredraw(void);
static void treset(void);
static void
panic(const char *m)
{
treset();
fprintf(stderr, "Panic: %s\n", m);
exit(1);
}
static void
sndf(const char *fmt, ...)
{
va_list vl;
size_t n, l=BufSz-(outp-outb);
if (l<2) return;
va_start(vl, fmt);
n=vsnprintf(outp, l-2, fmt, vl);
va_end(vl);
outp += n>l-2 ? l-2 : n;
*outp++ = '\r';
*outp++ = '\n';
}
static int
srd(void)
{
static char l[BufSz], *p=l;
char *s, *usr, *cmd, *par, *data;
int rd;
if (p-l>=BufSz) p=l; /* Input buffer overflow, there should something better to do. */
rd=read(sfd, p, BufSz-(p-l));
if (rd<0) {
if (errno==EINTR) return 1;
panic("IO error while reading.");
}
if (rd==0) return 0;
p+=rd;
for (;;) { /* Cycle on all received lines. */
if (!(s=memchr(l, '\n', p-l)))
return 1;
if (s>l && s[-1]=='\r')
s[-1]=0;
*s++ = 0;
if (*l==':') {
if (!(cmd=strchr(l, ' '))) goto lskip;
*cmd++ = 0;
usr = l+1;
} else {
usr = 0;
cmd = l;
}
if (!(par=strchr(cmd, ' '))) goto lskip;
*par++ = 0;
if ((data=strchr(par, ':')))
*data++ = 0;
scmd(usr, cmd, par, data);
lskip:
memmove(l, s, p-s);
p-=s-l;
}
}
static int
dial(const char *host, short port)
{
int f;
struct sockaddr_in sin;
struct addrinfo *ai, hai = { 0 };
hai.ai_family = AF_INET;
hai.ai_socktype = SOCK_STREAM;
if (getaddrinfo(host, 0, &hai, &ai))
panic("Cannot resolve host.");
memcpy(&sin, ai->ai_addr, sizeof sin);
sin.sin_port = htons(port);
freeaddrinfo(ai);
f = socket(AF_INET, SOCK_STREAM, 0);
if (f<0)
panic("Cannot create socket.");
if (connect(f, (struct sockaddr *)&sin, sizeof sin)<0)
panic("Cannot connect to host.");
return f;
}
static int
chadd(char *name)
{
if (nch>=MaxChans || strlen(name)>=ChanLen)
return -1;
strcpy(chl[nch].name, name);
chl[nch].sz=LogSz;
chl[nch].buf=malloc(LogSz);
if (!chl[nch].buf)
panic("Out of memory.");
chl[nch].eol=chl[nch].buf;
chl[nch].n=0;
ch=nch++;
tdrawbar();
return nch;
}
static inline int
chfind(char *name)
{
int i;
assert(name);
for (i=nch-1; i>0; i--)
if (!strcmp(chl[i].name, name))
break;
return i;
}
static int
chdel(char *name)
{
int n;
if (!(n=chfind(name))) return 0;
nch--;
free(chl[n].buf);
memmove(&chl[n], &chl[n+1], (nch-n)*sizeof(struct Chan));
ch=nch-1;
tdrawbar();
return 1;
}
static char *
pushl(char *p, char *e)
{
int x=0;
char *w;
if ((w=memchr(p, '\n', e-p))) e=w+1;
for (w=p;;) {
if (p>=e || *p==' ' || p-w+INDENT>=scr.x-1) {
for (; w<p; w++)
waddch(scr.mw, *w);
if (p>=e) return e;
}
p++;
if (++x>=scr.x) {
waddch(scr.mw, '\n');
for (x=0; x<INDENT; x++)
waddch(scr.mw, ' ');
if (*w==' ') w++;
x+=p-w;
}
}
}
static void
pushf(int cn, const char *fmt, ...)
{
struct Chan *const c=&chl[cn];
size_t n, blen=c->eol-c->buf;
va_list vl;
time_t t;
struct tm *tm;
if (blen+LineLen>=c->sz) {
c->sz *= 2;
c->buf=realloc(c->buf, c->sz);
if (!c->buf) panic("Out of memory.");
c->eol=c->buf+blen;
}
t=time(0);
if (!(tm=localtime(&t))) panic("Localtime failed.");
n=strftime(c->eol, LineLen, DATEFMT, tm);
c->eol[n++] = ' ';
va_start(vl, fmt);
n+=vsnprintf(c->eol+n, LineLen-n-1, fmt, vl);
va_end(vl);
strcat(c->eol, "\n");
if (n>=LineLen-1)
c->eol+=LineLen-1;
else
c->eol+=n+1;
if (cn==ch && c->n==0) {
char *p=c->eol-n-1;
if (p!=c->buf) waddch(scr.mw, '\n');
pushl(p, c->eol-1);
wrefresh(scr.mw);
}
}
static void
scmd(char *usr, char *cmd, char *par, char *data)
{
int s;
char *pm=strtok(par, " ");
if (!usr) usr="?";
else {
char *bang=strchr(usr, '!');
if (bang)
*bang=0;
}
if (!strcmp(cmd, "PRIVMSG")) {
if (!pm || !data) return;
pushf(chfind(pm), PFMT, usr, data);
} else if (!strcmp(cmd, "PING")) {
sndf("PONG :%s", data?data:"(null)");
} else if (!strcmp(cmd, "PART")) {
if (!pm) return;
pushf(chfind(pm), "-!- %s has left %s", usr, pm);
} else if (!strcmp(cmd, "JOIN")) {
if (!pm) return;
pushf(chfind(pm), "-!- %s has joined %s", usr, pm);
} else if (!strcmp(cmd, "470")) { /* Channel forwarding. */
char *ch=strtok(0, " "), *fch=strtok(0, " ");
if (!ch || !fch || !(s=chfind(ch))) return;
chl[s].name[0] = 0;
strncat(chl[s].name, fch, ChanLen-1);
tdrawbar();
} else if (!strcmp(cmd, "471") || !strcmp(cmd, "473")
|| !strcmp(cmd, "474") || !strcmp(cmd, "475")) { /* Join error. */
if ((pm=strtok(0, " "))) {
chdel(pm);
pushf(0, "-!- Cannot join channel %s (%s)", pm, cmd);
tredraw();
}
} else if (!strcmp(cmd, "QUIT")) { /* Commands we don't care about. */
return;
} else if (!strcmp(cmd, "NOTICE") || !strcmp(cmd, "375")
|| !strcmp(cmd, "372") || !strcmp(cmd, "376")) {
pushf(0, "%s", data?data:"");
} else
pushf(0, "%s - %s %s", cmd, par, data?data:"(null)");
}
static void
uparse(char *m)
{
char *p=m;
if (!p[0] || (p[1]!=' ' && p[1]!=0)) {
pmsg:
if (ch==0) return;
m+=strspn(m, " ");
if (!*m) return;
pushf(ch, PFMT, nick, m);
sndf("PRIVMSG %s :%s", chl[ch].name, m);
return;
}
switch (*p) {
case 'j': /* Join channels. */
p+=1+(p[1]==' ');
p=strtok(p, " ");
while (p) {
if (chadd(p)<0) break;
sndf("JOIN %s", p);
p=strtok(0, " ");
}
tredraw();
return;
case 'l': /* Leave channels. */
p+=1+(p[1]==' ');
if (!*p) {
if (ch==0) return; /* Cannot leave server window. */
strcat(p, chl[ch].name);
}
p=strtok(p, " ");
while (p) {
if (chdel(p))
sndf("PART %s", p);
p=strtok(0, " ");
}
tredraw();
return;
case 'm': /* Private message. */
m=p+1+(p[1]==' ');
if (!(p=strchr(m, ' '))) return;
*p++ = 0;
sndf("PRIVMSG %s :%s", m, p);
return;
case 'r': /* Send raw. */
if (p[1])
sndf("%s", &p[2]);
return;
case 'q': /* Quit. */
quit=1;
return;
default: /* Send on current channel. */
goto pmsg;
}
}
static void
sigwinch(int sig)
{
if (sig) winchg=1;
}
static void
tinit(void)
{
setlocale(LC_ALL, "");
signal(SIGWINCH, sigwinch);
initscr();
raw();
noecho();
getmaxyx(stdscr, scr.y, scr.x);
if (scr.y<4) panic("Screen too small.");
if ((scr.sw=newwin(1, scr.x, 0, 0))==0
|| (scr.mw=newwin(scr.y-2, scr.x, 1, 0))==0
|| (scr.iw=newwin(1, scr.x, scr.y-1, 0))==0)
panic("Cannot create windows.");
keypad(scr.iw, 1);
scrollok(scr.mw, 1);
if (has_colors()==TRUE) {
start_color();
init_pair(1, COLOR_WHITE, COLOR_BLUE);
wbkgd(scr.sw, COLOR_PAIR(1));
}
}
static void
tresize(void)
{
struct winsize ws;
winchg=0;
if (ioctl(0, TIOCGWINSZ, &ws)<0)
panic("Ioctl (TIOCGWINSZ) failed.");
resizeterm(scr.y=ws.ws_row, scr.x=ws.ws_col);
if (scr.y<3 || scr.x<10)
panic("Screen too small.");
wresize(scr.mw, scr.y-2, scr.x);
wresize(scr.iw, 1, scr.x);
wresize(scr.sw, 1, scr.x);
mvwin(scr.iw, scr.y-1, 0);
tredraw();
tdrawbar();
}
static void
tredraw(void)
{
struct Chan *const c=&chl[ch];
char *q, *p;
int llen=0, nl=-1;
if (c->eol==c->buf) {
wclear(scr.mw);
wrefresh(scr.mw);
return;
}
p=c->eol-1;
if (c->n) {
int i=c->n;
for (; p>c->buf; p--)
if (*p=='\n' && !i--) break;
if (p==c->buf) c->n-=i;
}
q=p;
while (nl<scr.y-2) {
llen=0;
while (*q!='\n' && q>c->buf)
q--, llen++;
nl += 1+llen/scr.x;
if (q==c->buf) break;
q--;
}
if (q!=c->buf) q+=2;
for (llen=0; nl>scr.y-2; ) { /* Maybe we must split the top line. */
if (q[llen]=='\n' || llen>=scr.x) {
q+=llen+(q[llen]=='\n');
llen=0;
nl--;
} else llen++;
}
wclear(scr.mw);
wmove(scr.mw, 0, 0);
while (q<p)
q=pushl(q, p);
wrefresh(scr.mw);
}
static void
tdrawbar(void)
{
size_t l;
int fst=ch;
for (l=0; fst>0 && l<scr.x/2; fst--)
l+=strlen(chl[fst].name)+3;
werase(scr.sw);
for (l=0; fst<nch && l<scr.x; fst++) {
char *p=chl[fst].name;
if (fst==ch) wattron(scr.sw, A_BOLD);
waddch(scr.sw, '['), l++;
for (; *p && l<scr.x; p++, l++)
waddch(scr.sw, *p);
if (l<scr.x-1)
waddstr(scr.sw, "] "), l+=2;
if (fst==ch) wattroff(scr.sw, A_BOLD);
}
wrefresh(scr.sw);
}
static void
tgetch(void)
{
static char l[BufSz];
static size_t shft, cu, len;
size_t dirty=len+1, i;
int c;
c=wgetch(scr.iw);
switch (c) {
case CTRL('n'):
ch=(ch+1)%nch;
tdrawbar();
tredraw();
return;
case CTRL('p'):
ch=(ch+nch-1)%nch;
tdrawbar();
tredraw();
return;
case KEY_PPAGE:
chl[ch].n+=SCROLL;
tredraw();
return;
case KEY_NPAGE:
chl[ch].n-=SCROLL;
if (chl[ch].n<0) chl[ch].n=0;
tredraw();
return;
case CTRL('a'):
cu=0;
break;
case CTRL('e'):
cu=len;
break;
case CTRL('b'):
case KEY_LEFT:
if (cu) cu--;
break;
case CTRL('f'):
case KEY_RIGHT:
if (cu<len) cu++;
break;
case CTRL('k'):
dirty=len=cu;
break;
case CTRL('u'):
if (cu==0) return;
len-=cu;
memmove(l, &l[cu], len);
dirty=cu=0;
break;
case CTRL('d'):
if (cu>=len) return;
memmove(&l[cu], &l[cu+1], len-cu-1);
dirty=cu;
len--;
break;
case KEY_BACKSPACE:
if (cu==0) return;
memmove(&l[cu-1], &l[cu], len-cu);
dirty=--cu;
len--;
break;
case '\n':
l[len]=0;
uparse(l);
dirty=cu=len=0;
break;
default:
if (c>CHAR_MAX || len>=BufSz-1) return; /* Skip other curses codes. */
memmove(&l[cu+1], &l[cu], len-cu);
dirty=cu;
len++;
l[cu++]=c;
break;
}
while (cu<shft)
dirty=0, shft -= shft>=scr.x/2 ? scr.x/2 : shft;
while (cu>=scr.x+shft)
dirty=0, shft += scr.x/2;
if (dirty<=shft)
i=shft;
else if (dirty>scr.x+shft || dirty>len)
goto mvcur;
else
i=dirty;
wmove(scr.iw, 0, i-shft);
wclrtoeol(scr.iw);
for (; i-shft<scr.x && i<len; i++)
waddch(scr.iw, l[i]);
mvcur: wmove(scr.iw, 0, cu-shft);
}
static void
treset(void)
{
if (scr.mw) delwin(scr.mw);
if (scr.sw) delwin(scr.sw);
if (scr.iw) delwin(scr.iw);
endwin();
}
int
main(int argc, char *argv[])
{
const char *user = getenv("USER");
const char *ircnick = getenv("IRCNICK");
const char *server = SRV;
unsigned short port = PORT;
int o;
while ((o=getopt(argc, argv, "hn:u:s:p:"))>=0)
switch (o) {
case 'h':
case '?':
usage:
fputs("Usage: irc [-n NICK] [-u USER] [-s SERVER] [-p PORT] [-h]\n", stderr);
exit(0);
case 'n':
if (strlen(optarg)>=sizeof nick) goto usage;
strcpy(nick, optarg);
break;
case 'u':
user = optarg;
break;
case 's':
server = optarg;
break;
case 'p':
if (!(port=strtol(optarg, 0, 0))) goto usage;
break;
}
if (!nick[0] && ircnick && strlen(ircnick)<sizeof nick)
strcpy(nick, ircnick);
if (!nick[0]) goto usage;
if (!user) user = "Unknown";
tinit();
sfd = dial(server, port);
chadd("*server*");
sndf("NICK %s", nick);
sndf("USER %s 8 * :%s", user, user);
sndf("MODE %s +i", nick);
while (!quit) {
fd_set rfs, wfs;
int ret;
if (winchg)
tresize();
FD_ZERO(&wfs);
FD_ZERO(&rfs);
FD_SET(0, &rfs);
FD_SET(sfd, &rfs);
if (outp!=outb)
FD_SET(sfd, &wfs);
ret=select(sfd+1, &rfs, &wfs, 0, 0);
if (ret<0) {
if (errno==EINTR) continue;
panic("Select failed.");
}
if (FD_ISSET(sfd, &rfs)) {
if (!srd())
quit=1;
}
if (FD_ISSET(sfd, &wfs)) {
int wr;
wr=write(sfd, outb, outp-outb);
if (wr<0) {
if (errno==EINTR) continue;
panic("Write error.");
}
if (wr==0) continue;
outp-=wr;
memmove(outb, outb+wr, outp-outb);
}
if (FD_ISSET(0, &rfs)) {
tgetch();
wrefresh(scr.iw);
}
}
close(sfd);
while (nch--)
free(chl[nch].buf);
treset();
exit(0);
}
File diff suppressed because it is too large Load Diff