#include #include #include #include #include #include #include #define F "r.db" #define J "reminder@example.org" #define P "safak" #define R "remiders@room.example.org" #define N "ReminderBot" typedef struct E{long long i;char*r,*u,*m;time_t d;struct E*n;}E; typedef struct{xmpp_ctx_t*c;xmpp_conn_t*o;E*l;long long k;}B; static void T(xmpp_ctx_t*c,xmpp_stanza_t*p,const char*t){ xmpp_stanza_t*n=xmpp_stanza_new(c); xmpp_stanza_set_text(n,t); xmpp_stanza_add_child(p,n); xmpp_stanza_release(n); } static time_t pt(const char*s){ time_t w=time(0);struct tm t=*localtime(&w);int h,m; if(strchr(s,':')&&sscanf(s,"%d:%d",&h,&m)==2){ struct tm f=t;f.tm_hour=h;f.tm_min=m;f.tm_sec=0; time_t x=mktime(&f);return x<=w?x+86400:x; } char*e;long v=strtol(s,&e,10);if(e==s)return 0; char a=tolower(*e),b=e[1]?tolower(e[1]):0; if(a=='s')return w+v; if(a=='m'&&b!='o')return w+v*60; if(a=='h')return w+v*3600; if(a=='d')return w+v*86400; if(a=='w')return w+v*604800; if(a=='m'&&b=='o'){int n=t.tm_mon+v;t.tm_year+=n/12;t.tm_mon=n%12;if(t.tm_mon<0){t.tm_mon+=12;t.tm_year--;}return mktime(&t);} if(a=='y'){int n=t.tm_mon+v*12;t.tm_year+=n/12;t.tm_mon=n%12;return mktime(&t);} return 0; } static void sv(B*b){ FILE*f=fopen(F,"wb");if(!f)return; int64_t c=b->k;fwrite(&c,8,1,f); for(E*r=b->l;r;r=r->n){ int64_t i=r->i,d=r->d; uint16_t a=strlen(r->r),e=strlen(r->u),g=strlen(r->m); fwrite(&i,8,1,f);fwrite(&d,8,1,f); fwrite(&a,2,1,f);fwrite(&e,2,1,f);fwrite(&g,2,1,f); fwrite(r->r,1,a,f);fwrite(r->u,1,e,f);fwrite(r->m,1,g,f); } fclose(f); } static void ld(B*b){ FILE*f=fopen(F,"rb");if(!f)return; int64_t c;if(fread(&c,8,1,f)!=1){fclose(f);return;} b->k=c;int64_t i; while(fread(&i,8,1,f)==1){ int64_t d;uint16_t a,e,g; if(fread(&d,8,1,f)!=1||fread(&a,2,1,f)!=1||fread(&e,2,1,f)!=1||fread(&g,2,1,f)!=1)break; E*r=malloc(sizeof(E));r->i=i;r->d=d; r->r=malloc(a+1);r->u=malloc(e+1);r->m=malloc(g+1); if(fread(r->r,1,a,f)!=a||fread(r->u,1,e,f)!=e||fread(r->m,1,g,f)!=g){free(r->r);free(r->u);free(r->m);free(r);break;} r->r[a]=r->u[e]=r->m[g]=0;r->n=b->l;b->l=r; } fclose(f); } static void rp(B*b,const char*t,const char*y,const char*m){ xmpp_stanza_t*s=xmpp_stanza_new(b->c); xmpp_stanza_set_name(s,"message"); xmpp_stanza_set_type(s,y); xmpp_stanza_set_attribute(s,"to",t); xmpp_stanza_t*o=xmpp_stanza_new(b->c); xmpp_stanza_set_name(o,"body"); T(b->c,o,m); xmpp_stanza_add_child(s,o); xmpp_stanza_release(o); xmpp_send(b->o,s); xmpp_stanza_release(s); } static int tc(xmpp_conn_t*o,void*x){ B*b=x;time_t w=time(0);E**p=&b->l;int z=0; while(*p){ E*r=*p; if(w>=r->d){ char q[2048];snprintf(q,2048,"%s: %s",r->u,r->m); rp(b,r->r,strstr(r->r,"@conf")||strstr(r->r,"@muc")?"groupchat":"chat",q); *p=r->n;free(r->r);free(r->u);free(r->m);free(r);z=1; }else p=&r->n; } if(z)sv(b);return 1; } static int mc(xmpp_conn_t*o,xmpp_stanza_t*s,void*x){ B*b=x; xmpp_stanza_t*y=xmpp_stanza_get_child_by_name(s,"body"); if(!y)return 1; char*t=xmpp_stanza_get_text(y); if(!t||*t!='!'){if(t)xmpp_free(b->c,t);return 1;} const char*f=xmpp_stanza_get_attribute(s,"from"); const char*p=xmpp_stanza_get_attribute(s,"type"); if(!p)p="chat"; if(!strcmp(p,"groupchat")){const char*l=strchr(f,'/');if(l&&!strcmp(l+1,N)){xmpp_free(b->c,t);return 1;}} char*e=strdup(t),*c=strtok(e," "),rm[512],us[256]; const char*l=strchr(f,'/'); if(l){size_t n=l-f;memcpy(rm,f,n);rm[n]=0;strncpy(us,l+1,255);us[255]=0;} else{strncpy(rm,f,511);strncpy(us,f,255);} if(c&&!strcmp(c,"!remind")){ char*ts=strtok(0," "),*mg=strtok(0,""); if(ts&&mg){ time_t d=pt(ts); if(d>0){ E*r=malloc(sizeof(E));r->i=++b->k;r->r=strdup(rm);r->u=strdup(us);r->m=strdup(mg);r->d=d;r->n=b->l;b->l=r;sv(b); struct tm*z=localtime(&d);char q[256]; snprintf(q,256,"Saved [%lld]: %04d-%02d-%02d %02d:%02d:%02d",r->i,z->tm_year+1900,z->tm_mon+1,z->tm_mday,z->tm_hour,z->tm_min,z->tm_sec); rp(b,rm,p,q); }else rp(b,rm,p,"Invalid format. Try: 30s, 5m, 1h, 10:30"); }else rp(b,rm,p,"Usage: !remind