Changes in / [aa31117:b79308b]
- Files:
-
- 5 added
- 13 edited
Legend:
- Unmodified
- Added
- Removed
-
Makefile
raa31117 rb79308b 10 10 11 11 # Program variables 12 objects = account.o bitlbee.o conf.o crypting.o help.o ipc.o irc.o irc_commands.o log.o nick.o query.o root_commands.o set.o storage.o $(STORAGE_OBJS) unix.o user.o 13 headers = account.h bitlbee.h commands.h conf.h config.h crypting.h help.h ipc.h irc.h log.h nick.h query.h set.h sock.h storage.h user.h lib/events.h lib/http_client.h lib/ini.h lib/md5.h lib/misc.h lib/proxy.h lib/sha1.h lib/ssl_client.h lib/url.h protocols/nogaim.h12 objects = account.o bitlbee.o conf.o crypting.o help.o ipc.o irc.o irc_commands.o log.o nick.o query.o root_commands.o set.o storage.o $(STORAGE_OBJS) unix.o user.o dcc.o 13 headers = account.h bitlbee.h commands.h conf.h config.h crypting.h help.h ipc.h irc.h log.h nick.h query.h set.h sock.h storage.h user.h dcc.h lib/events.h lib/http_client.h lib/ini.h lib/md5.h lib/misc.h lib/proxy.h lib/sha1.h lib/ssl_client.h lib/url.h protocols/nogaim.h protocols/ft.h 14 14 subdirs = lib protocols 15 15 -
conf.c
raa31117 rb79308b 62 62 conf->ping_timeout = 300; 63 63 conf->user = NULL; 64 conf->max_filetransfer_size = G_MAXUINT; 64 65 proxytype = 0; 65 66 -
conf.h
raa31117 rb79308b 50 50 int ping_timeout; 51 51 char *user; 52 size_t max_filetransfer_size; 52 53 } conf_t; 53 54 -
doc/user-guide/commands.xml
raa31117 rb79308b 874 874 875 875 </bitlbee-command> 876 877 <bitlbee-command name="transfers"> 878 <short-description>Monitor, cancel, or reject file transfers</short-description> 879 <syntax>transfers [<cancel> id | <reject>]</syntax> 880 881 <description> 882 <para> 883 Without parameters the currently pending file transfers and their status will be listed. Available actions are <emphasis>cancel</emphasis> and <emphasis>reject</emphasis>. See <emphasis>help transfers <action></emphasis> for more information. 884 </para> 885 886 <ircexample> 887 <ircline nick="ulim">transfers</ircline> 888 </ircexample> 889 </description> 890 891 <bitlbee-command name="cancel"> 892 <short-description>Cancels the file transfer with the given id</short-description> 893 <syntax>transfers <cancel> id</syntax> 894 895 <description> 896 <para>Cancels the file transfer with the given id</para> 897 </description> 898 899 <ircexample> 900 <ircline nick="ulim">transfers cancel 1</ircline> 901 <ircline nick="root">Canceling file transfer for test</ircline> 902 </ircexample> 903 </bitlbee-command> 904 905 <bitlbee-command name="reject"> 906 <short-description>Rejects all incoming transfers</short-description> 907 <syntax>transfers <reject></syntax> 908 909 <description> 910 <para>Rejects all incoming (not already transferring) file transfers. Since you probably have only one incoming transfer at a time, no id is neccessary. Or is it?</para> 911 </description> 912 913 <ircexample> 914 <ircline nick="ulim">transfers reject</ircline> 915 </ircexample> 916 </bitlbee-command> 917 </bitlbee-command> 918 876 919 </chapter> -
irc.c
raa31117 rb79308b 28 28 #include "crypting.h" 29 29 #include "ipc.h" 30 #include "dcc.h" 31 32 #include <regex.h> 33 #include <netinet/in.h> 30 34 31 35 static gboolean irc_userping( gpointer _irc, int fd, b_input_condition cond ); … … 1070 1074 return( 1 ); 1071 1075 } 1076 else if( g_strncasecmp( s + 1, "DCC", 3 ) == 0 ) 1077 { 1078 if( u && u->ic && u->ic->acc->prpl->transfer_request ) 1079 { 1080 file_transfer_t *ft = dcc_request( u->ic, s + 5 ); 1081 if ( ft ) 1082 u->ic->acc->prpl->transfer_request( u->ic, ft, u->handle ); 1083 } 1084 return( 1 ); 1085 } 1072 1086 else 1073 1087 { 1074 irc_usermsg( irc, " Non-ACTION CTCP's aren't supported" );1088 irc_usermsg( irc, "Supported CTCPs are ACTION, VERSION, PING, TYPING, DCC" ); 1075 1089 return( 0 ); 1076 1090 } -
irc.h
raa31117 rb79308b 87 87 struct query *queries; 88 88 struct account *accounts; 89 GSList *file_transfers; 89 90 90 91 struct __USER *users; -
protocols/jabber/Makefile
raa31117 rb79308b 10 10 11 11 # [SH] Program variables 12 objects = conference.o io.o iq.o jabber.o jabber_util.o message.o presence.o sasl.o 12 objects = conference.o io.o iq.o jabber.o jabber_util.o message.o presence.o sasl.o si.o s5bytestream.o 13 13 14 14 CFLAGS += -Wall -
protocols/jabber/iq.c
raa31117 rb79308b 90 90 pack = 0; 91 91 } 92 else if( strcmp( s, XMLNS_DISCO VER) == 0 )93 { 94 const char *features[] = { XMLNS_DISCO VER,92 else if( strcmp( s, XMLNS_DISCO_INFO ) == 0 ) 93 { 94 const char *features[] = { XMLNS_DISCO_INFO, 95 95 XMLNS_VERSION, 96 96 XMLNS_TIME, … … 98 98 XMLNS_MUC, 99 99 XMLNS_PING, 100 XMLNS_SI, 101 XMLNS_BYTESTREAMS, 102 XMLNS_FILETRANSFER, 100 103 NULL }; 101 104 const char **f; … … 117 120 { 118 121 xt_free_node( reply ); 119 reply = jabber_make_error_packet( node, "feature-not-implemented", "cancel" );122 reply = jabber_make_error_packet( node, "feature-not-implemented", "cancel", NULL ); 120 123 pack = 0; 121 124 } … … 123 126 else if( strcmp( type, "set" ) == 0 ) 124 127 { 125 if( !( c = xt_find_node( node->children, "query" ) ) || 128 if( ( c = xt_find_node( node->children, "si" ) ) && 129 ( strcmp( xt_find_attr( c, "xmlns" ), XMLNS_SI ) == 0 ) ) 130 { 131 return jabber_si_handle_request( ic, node, c ); 132 } else if( !( c = xt_find_node( node->children, "query" ) ) || 126 133 !( s = xt_find_attr( c, "xmlns" ) ) ) 127 134 { 128 135 imcb_log( ic, "Warning: Received incomplete IQ-%s packet", type ); 129 136 return XT_HANDLED; 130 } 131 137 } else if( strcmp( s, XMLNS_ROSTER ) == 0 ) 138 { 132 139 /* This is a roster push. XMPP servers send this when someone 133 140 was added to (or removed from) the buddy list. AFAIK they're 134 141 sent even if we added this buddy in our own session. */ 135 if( strcmp( s, XMLNS_ROSTER ) == 0 )136 {137 142 int bare_len = strlen( ic->acc->user ); 138 143 … … 151 156 152 157 xt_free_node( reply ); 153 reply = jabber_make_error_packet( node, "not-allowed", "cancel" );158 reply = jabber_make_error_packet( node, "not-allowed", "cancel", NULL ); 154 159 pack = 0; 155 160 } 156 } 157 else 161 } else if( strcmp( s, XMLNS_BYTESTREAMS ) == 0 ) 162 { 163 /* Bytestream Request (stage 2 of file transfer) */ 164 return jabber_bs_recv_request( ic, node, c ); 165 } else 158 166 { 159 167 xt_free_node( reply ); 160 reply = jabber_make_error_packet( node, "feature-not-implemented", "cancel" );168 reply = jabber_make_error_packet( node, "feature-not-implemented", "cancel", NULL ); 161 169 pack = 0; 162 170 } … … 593 601 return st; 594 602 } 603 604 xt_status jabber_iq_parse_features( struct im_connection *ic, struct xt_node *node, struct xt_node *orig ); 605 606 xt_status jabber_iq_query_features( struct im_connection *ic, char *bare_jid ) 607 { 608 struct xt_node *node, *query; 609 struct jabber_buddy *bud; 610 611 if( ( bud = jabber_buddy_by_jid( ic, bare_jid , 0 ) ) == NULL ) 612 { 613 /* Who cares about the unknown... */ 614 imcb_log( ic, "Couldnt find the man: %s", bare_jid); 615 return 0; 616 } 617 618 if( bud->features ) /* been here already */ 619 return XT_HANDLED; 620 621 node = xt_new_node( "query", NULL, NULL ); 622 xt_add_attr( node, "xmlns", XMLNS_DISCO_INFO ); 623 624 if( !( query = jabber_make_packet( "iq", "get", bare_jid, node ) ) ) 625 { 626 imcb_log( ic, "WARNING: Couldn't generate feature query" ); 627 xt_free_node( node ); 628 } 629 630 jabber_cache_add( ic, query, jabber_iq_parse_features ); 631 632 return jabber_write_packet( ic, query ); 633 } 634 635 xt_status jabber_iq_parse_features( struct im_connection *ic, struct xt_node *node, struct xt_node *orig ) 636 { 637 struct xt_node *c; 638 struct jabber_buddy *bud; 639 char *feature; 640 641 if( !( c = xt_find_node( node->children, "query" ) ) || 642 !( strcmp( xt_find_attr( c, "xmlns" ), XMLNS_DISCO_INFO ) == 0 ) ) 643 { 644 imcb_log( ic, "WARNING: Received incomplete IQ-result packet for discover" ); 645 return XT_HANDLED; 646 } 647 if( ( bud = jabber_buddy_by_jid( ic, xt_find_attr( node, "from") , 0 ) ) == NULL ) 648 { 649 /* Who cares about the unknown... */ 650 imcb_log( ic, "Couldnt find the man: %s", xt_find_attr( node, "from")); 651 return 0; 652 } 653 654 c = c->children; 655 while( ( c = xt_find_node( c, "feature" ) ) ) { 656 feature = xt_find_attr( c, "var" ); 657 bud->features = g_slist_append(bud->features, g_strdup(feature) ); 658 c = c->next; 659 } 660 661 return XT_HANDLED; 662 } 663 664 xt_status jabber_iq_parse_server_features( struct im_connection *ic, struct xt_node *node, struct xt_node *orig ); 665 666 xt_status jabber_iq_query_server( struct im_connection *ic, char *jid, char *xmlns ) 667 { 668 struct xt_node *node, *query; 669 struct jabber_data *jd = ic->proto_data; 670 671 node = xt_new_node( "query", NULL, NULL ); 672 xt_add_attr( node, "xmlns", xmlns ); 673 674 if( !( query = jabber_make_packet( "iq", "get", jid, node ) ) ) 675 { 676 imcb_log( ic, "WARNING: Couldn't generate server query" ); 677 xt_free_node( node ); 678 } 679 680 jd->have_streamhosts--; 681 jabber_cache_add( ic, query, jabber_iq_parse_server_features ); 682 683 return jabber_write_packet( ic, query ); 684 } 685 686 /* 687 * Query the server for "items", query each "item" for identities, query each "item" that's a proxy for it's bytestream info 688 */ 689 xt_status jabber_iq_parse_server_features( struct im_connection *ic, struct xt_node *node, struct xt_node *orig ) 690 { 691 struct xt_node *c; 692 struct jabber_data *jd = ic->proto_data; 693 694 if( !( c = xt_find_node( node->children, "query" ) ) || 695 !xt_find_attr( node, "from" ) ) 696 { 697 imcb_log( ic, "WARNING: Received incomplete IQ-result packet for discover" ); 698 return XT_HANDLED; 699 } 700 701 jd->have_streamhosts++; 702 703 if( strcmp( xt_find_attr( c, "xmlns" ), XMLNS_DISCO_ITEMS ) == 0 ) 704 { 705 char *item, *itemjid; 706 707 /* answer from server */ 708 709 c = c->children; 710 while( ( c = xt_find_node( c, "item" ) ) ) 711 { 712 item = xt_find_attr( c, "name" ); 713 itemjid = xt_find_attr( c, "jid" ); 714 715 jabber_iq_query_server( ic, itemjid, XMLNS_DISCO_INFO ); 716 717 c = c->next; 718 } 719 } else if( strcmp( xt_find_attr( c, "xmlns" ), XMLNS_DISCO_INFO ) == 0 ) 720 { 721 char *category, *type; 722 723 /* answer from potential proxy */ 724 725 c = c->children; 726 while( ( c = xt_find_node( c, "identity" ) ) ) 727 { 728 category = xt_find_attr( c, "category" ); 729 type = xt_find_attr( c, "type" ); 730 731 if( type && ( strcmp( type, "bytestreams" ) == 0 ) && 732 category && ( strcmp( category, "proxy" ) == 0 ) ) 733 jabber_iq_query_server( ic, xt_find_attr( node, "from" ), XMLNS_BYTESTREAMS ); 734 735 c = c->next; 736 } 737 } else if( strcmp( xt_find_attr( c, "xmlns" ), XMLNS_BYTESTREAMS ) == 0 ) 738 { 739 char *host, *jid; 740 int port; 741 742 /* answer from proxy */ 743 744 if( ( c = xt_find_node( c->children, "streamhost" ) ) && 745 ( host = xt_find_attr( c, "host" ) ) && 746 ( port = atoi( xt_find_attr( c, "port" ) ) ) && 747 ( jid = xt_find_attr( c, "jid" ) ) ) 748 { 749 jabber_streamhost_t *sh = g_new0( jabber_streamhost_t, 1 ); 750 sh->jid = g_strdup( jid ); 751 sh->host = g_strdup( host ); 752 sprintf( sh->port, "%u", port ); 753 754 imcb_log( ic, "Proxy found: jid %s host %s port %u", jid, host, port ); 755 jd->streamhosts = g_slist_append( jd->streamhosts, sh ); 756 } 757 } 758 759 if( jd->have_streamhosts == 0 ) 760 jd->have_streamhosts++; 761 return XT_HANDLED; 762 } -
protocols/jabber/jabber.c
raa31117 rb79308b 530 530 ret->send_typing = jabber_send_typing; 531 531 ret->handle_cmp = g_strcasecmp; 532 ret->transfer_request = jabber_si_transfer_request; 532 533 533 534 register_protocol( ret ); -
protocols/jabber/jabber.h
raa31117 rb79308b 59 59 } jabber_buddy_flags_t; 60 60 61 /* Stores a streamhost's(a.k.a. proxy) data */ 62 typedef struct 63 { 64 char *jid; 65 char *host; 66 char port[6]; 67 } jabber_streamhost_t; 68 61 69 typedef enum 62 70 { … … 89 97 GHashTable *node_cache; 90 98 GHashTable *buddies; 99 100 GSList *filetransfers; 101 GSList *streamhosts; 102 int have_streamhosts; 91 103 }; 92 104 … … 118 130 struct jabber_away_state *away_state; 119 131 char *away_message; 132 GSList *features; 120 133 121 134 time_t last_act; … … 131 144 char *my_full_jid; /* Separate copy because of case sensitivity. */ 132 145 struct jabber_buddy *me; 146 }; 147 148 struct jabber_transfer 149 { 150 /* bitlbee's handle for this transfer */ 151 file_transfer_t *ft; 152 153 /* the stream's private handle */ 154 gpointer streamhandle; 155 156 struct im_connection *ic; 157 158 int watch_in; 159 int watch_out; 160 161 char *ini_jid; 162 char *tgt_jid; 163 char *iq_id; 164 char *sid; 165 int accepted; 166 167 size_t bytesread, byteswritten; 168 int fd; 169 struct sockaddr_storage saddr; 133 170 }; 134 171 … … 162 199 163 200 /* Some supported extensions/legacy stuff */ 164 #define XMLNS_AUTH "jabber:iq:auth" /* XEP-0078 */ 165 #define XMLNS_VERSION "jabber:iq:version" /* XEP-0092 */ 166 #define XMLNS_TIME "jabber:iq:time" /* XEP-0090 */ 167 #define XMLNS_PING "urn:xmpp:ping" /* XEP-0199 */ 168 #define XMLNS_VCARD "vcard-temp" /* XEP-0054 */ 169 #define XMLNS_DELAY "jabber:x:delay" /* XEP-0091 */ 170 #define XMLNS_CHATSTATES "http://jabber.org/protocol/chatstates" /* 0085 */ 171 #define XMLNS_DISCOVER "http://jabber.org/protocol/disco#info" /* 0030 */ 172 #define XMLNS_MUC "http://jabber.org/protocol/muc" /* XEP-0045 */ 173 #define XMLNS_MUC_USER "http://jabber.org/protocol/muc#user"/* XEP-0045 */ 174 #define XMLNS_CAPS "http://jabber.org/protocol/caps" /* XEP-0115 */ 201 #define XMLNS_AUTH "jabber:iq:auth" /* XEP-0078 */ 202 #define XMLNS_VERSION "jabber:iq:version" /* XEP-0092 */ 203 #define XMLNS_TIME "jabber:iq:time" /* XEP-0090 */ 204 #define XMLNS_PING "urn:xmpp:ping" /* XEP-0199 */ 205 #define XMLNS_VCARD "vcard-temp" /* XEP-0054 */ 206 #define XMLNS_DELAY "jabber:x:delay" /* XEP-0091 */ 207 #define XMLNS_XDATA "jabber:x:data" /* XEP-0004 */ 208 #define XMLNS_CHATSTATES "http://jabber.org/protocol/chatstates" /* XEP-0085 */ 209 #define XMLNS_DISCO_INFO "http://jabber.org/protocol/disco#info" /* XEP-0030 */ 210 #define XMLNS_DISCO_ITEMS "http://jabber.org/protocol/disco#items" /* XEP-0030 */ 211 #define XMLNS_MUC "http://jabber.org/protocol/muc" /* XEP-0045 */ 212 #define XMLNS_MUC_USER "http://jabber.org/protocol/muc#user" /* XEP-0045 */ 213 #define XMLNS_CAPS "http://jabber.org/protocol/caps" /* XEP-0115 */ 214 #define XMLNS_FEATURE "http://jabber.org/protocol/feature-neg" /* XEP-0020 */ 215 #define XMLNS_SI "http://jabber.org/protocol/si" /* XEP-0095 */ 216 #define XMLNS_FILETRANSFER "http://jabber.org/protocol/si/profile/file-transfer" /* XEP-0096 */ 217 #define XMLNS_BYTESTREAMS "http://jabber.org/protocol/bytestreams" /* XEP-0065 */ 218 #define XMLNS_IBB "http://jabber.org/protocol/ibb" /* XEP-0047 */ 175 219 176 220 /* iq.c */ … … 182 226 int jabber_add_to_roster( struct im_connection *ic, char *handle, char *name ); 183 227 int jabber_remove_from_roster( struct im_connection *ic, char *handle ); 228 xt_status jabber_iq_query_features( struct im_connection *ic, char *bare_jid ); 229 xt_status jabber_iq_query_server( struct im_connection *ic, char *jid, char *xmlns ); 230 231 /* si.c */ 232 int jabber_si_handle_request( struct im_connection *ic, struct xt_node *node, struct xt_node *sinode ); 233 void jabber_si_transfer_request( struct im_connection *ic, file_transfer_t *ft, char *who ); 234 void jabber_si_free_transfer( file_transfer_t *ft); 235 236 /* s5bytestream.c */ 237 int jabber_bs_recv_request( struct im_connection *ic, struct xt_node *node, struct xt_node *qnode); 238 gboolean jabber_bs_send_start( struct jabber_transfer *tf ); 239 gboolean jabber_bs_send_write( file_transfer_t *ft, char *buffer, unsigned int len ); 184 240 185 241 /* message.c */ … … 195 251 char *set_eval_tls( set_t *set, char *value ); 196 252 struct xt_node *jabber_make_packet( char *name, char *type, char *to, struct xt_node *children ); 197 struct xt_node *jabber_make_error_packet( struct xt_node *orig, char *err_cond, char *err_type );253 struct xt_node *jabber_make_error_packet( struct xt_node *orig, char *err_cond, char *err_type, char *err_code ); 198 254 void jabber_cache_add( struct im_connection *ic, struct xt_node *node, jabber_cache_event func ); 199 255 struct xt_node *jabber_cache_get( struct im_connection *ic, char *id ); -
protocols/jabber/jabber_util.c
raa31117 rb79308b 97 97 } 98 98 99 struct xt_node *jabber_make_error_packet( struct xt_node *orig, char *err_cond, char *err_type )99 struct xt_node *jabber_make_error_packet( struct xt_node *orig, char *err_cond, char *err_type, char *err_code ) 100 100 { 101 101 struct xt_node *node, *c; … … 109 109 c = xt_new_node( "error", NULL, c ); 110 110 xt_add_attr( c, "type", err_type ); 111 112 /* Add the error code, if present */ 113 if (err_code) 114 xt_add_attr( c, "code", err_code ); 111 115 112 116 /* To make the actual error packet, we copy the original packet and … … 291 295 new = g_new( char, len + 1 ); 292 296 for( i = 0; i < len; i ++ ) 297 { 298 /* don't normalize the resource */ 299 if( orig[i] == '/' ) 300 break; 293 301 new[i] = tolower( orig[i] ); 302 } 303 for( ; i < len; i ++ ) 304 new[i] = orig[i]; 294 305 295 306 new[i] = 0; -
protocols/nogaim.h
raa31117 rb79308b 44 44 #include "query.h" 45 45 #include "md5.h" 46 #include "ft.h" 46 47 47 48 #define BUF_LEN MSG_LEN … … 229 230 * - Most protocols will just want to set this to g_strcasecmp().*/ 230 231 int (* handle_cmp) (const char *who1, const char *who2); 232 233 /* Incoming transfer request */ 234 void (* transfer_request) (struct im_connection *, file_transfer_t *ft, char *handle ); 231 235 }; 232 236 -
root_commands.c
raa31117 rb79308b 1035 1035 irc_usermsg( irc, "Tried to join chat, not sure if this was successful" ); 1036 1036 g_free( channel ); 1037 } 1038 } 1039 1040 static void cmd_transfers( irc_t *irc, char **cmd ) 1041 { 1042 GSList *files = irc->file_transfers; 1043 enum { LIST, REJECT, CANCEL }; 1044 int subcmd = LIST; 1045 int fid; 1046 1047 if( !files ) 1048 { 1049 irc_usermsg( irc, "No pending transfers" ); 1050 return; 1051 } 1052 1053 if( cmd[1] && 1054 ( strcmp( cmd[1], "reject" ) == 0 ) ) 1055 { 1056 subcmd = REJECT; 1057 } 1058 else if( cmd[1] && 1059 ( strcmp( cmd[1], "cancel" ) == 0 ) && 1060 cmd[2] && 1061 ( fid = atoi( cmd[2] ) ) ) 1062 { 1063 subcmd = CANCEL; 1064 } 1065 1066 for( ; files; files = g_slist_next( files ) ) 1067 { 1068 file_transfer_t *file = files->data; 1069 1070 switch( subcmd ) { 1071 case LIST: 1072 if ( file->status == FT_STATUS_LISTENING ) 1073 irc_usermsg( irc, 1074 "Pending file(id %d): %s (Listening...)", file->local_id, file->file_name); 1075 else 1076 { 1077 int kb_per_s = 0; 1078 time_t diff = time( NULL ) - file->started; 1079 if ( ( file->started > 0 ) && ( file->bytes_transferred > 0 ) ) 1080 kb_per_s = file->bytes_transferred / 1024 / diff; 1081 1082 irc_usermsg( irc, 1083 "Pending file(id %d): %s (%10zd/%zd kb, %d kb/s)", file->local_id, file->file_name, 1084 file->bytes_transferred/1024, file->file_size/1024, kb_per_s); 1085 } 1086 break; 1087 case REJECT: 1088 if( file->status == FT_STATUS_LISTENING ) 1089 { 1090 irc_usermsg( irc, "Rejecting file transfer for %s", file->file_name ); 1091 imcb_file_canceled( file, "Denied by user" ); 1092 } 1093 break; 1094 case CANCEL: 1095 if( file->local_id == fid ) 1096 { 1097 irc_usermsg( irc, "Canceling file transfer for %s", file->file_name ); 1098 imcb_file_canceled( file, "Canceled by user" ); 1099 } 1100 break; 1101 } 1037 1102 } 1038 1103 } … … 1058 1123 { "qlist", 0, cmd_qlist, 0 }, 1059 1124 { "join_chat", 2, cmd_join_chat, 0 }, 1125 { "transfers", 0, cmd_transfers, 0 }, 1060 1126 { NULL } 1061 1127 };
Note: See TracChangeset
for help on using the changeset viewer.