Line data Source code
1 : /* 2 : Mosh: the mobile shell 3 : Copyright 2012 Keith Winstein 4 : 5 : This program is free software: you can redistribute it and/or modify 6 : it under the terms of the GNU General Public License as published by 7 : the Free Software Foundation, either version 3 of the License, or 8 : (at your option) any later version. 9 : 10 : This program is distributed in the hope that it will be useful, 11 : but WITHOUT ANY WARRANTY; without even the implied warranty of 12 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 : GNU General Public License for more details. 14 : 15 : You should have received a copy of the GNU General Public License 16 : along with this program. If not, see <http://www.gnu.org/licenses/>. 17 : 18 : In addition, as a special exception, the copyright holders give 19 : permission to link the code of portions of this program with the 20 : OpenSSL library under certain conditions as described in each 21 : individual source file, and distribute linked combinations including 22 : the two. 23 : 24 : You must obey the GNU General Public License in all respects for all 25 : of the code used other than OpenSSL. If you modify file(s) with this 26 : exception, you may extend this exception to your version of the 27 : file(s), but you are not obligated to do so. If you do not wish to do 28 : so, delete this exception statement from your version. If you delete 29 : this exception statement from all source files in the program, then 30 : also delete it here. 31 : */ 32 : 33 : #include <assert.h> 34 : #include <typeinfo> 35 : 36 : #include "user.h" 37 : #include "fatal_assert.h" 38 : #include "userinput.pb.h" 39 : 40 : using namespace Parser; 41 : using namespace Network; 42 : using namespace ClientBuffers; 43 : 44 29999 : void UserStream::subtract( const UserStream *prefix ) 45 : { 46 : // if we are subtracting ourself from ourself, just clear the deque 47 29999 : if ( this == prefix ) { 48 13674 : actions.clear(); 49 13674 : return; 50 : } 51 19675 : for ( deque<UserEvent>::const_iterator i = prefix->actions.begin(); 52 19675 : i != prefix->actions.end(); 53 : i++ ) { 54 3350 : assert( this != prefix ); 55 3350 : assert( !actions.empty() ); 56 3350 : assert( *i == actions.front() ); 57 3350 : actions.pop_front(); 58 : } 59 : } 60 : 61 3937 : string UserStream::diff_from( const UserStream &existing ) const 62 : { 63 3937 : deque<UserEvent>::const_iterator my_it = actions.begin(); 64 : 65 3937 : for ( deque<UserEvent>::const_iterator i = existing.actions.begin(); 66 5614 : i != existing.actions.end(); 67 : i++ ) { 68 1677 : assert( my_it != actions.end() ); 69 1677 : assert( *i == *my_it ); 70 1677 : my_it++; 71 : } 72 : 73 3937 : ClientBuffers::UserMessage output; 74 : 75 7332 : while ( my_it != actions.end() ) { 76 3395 : switch ( my_it->type ) { 77 2369 : case UserByteType: 78 2369 : { 79 2369 : char the_byte = my_it->userbyte.c; 80 : /* can we combine this with a previous Keystroke? */ 81 2369 : if ( (output.instruction_size() > 0) 82 2369 : && (output.instruction( output.instruction_size() - 1 ).HasExtension( keystroke )) ) { 83 2132 : output.mutable_instruction( output.instruction_size() - 1 )->MutableExtension( keystroke )->mutable_keys()->append( string( &the_byte, 1 ) ); 84 : } else { 85 1303 : Instruction *new_inst = output.add_instruction(); 86 1303 : new_inst->MutableExtension( keystroke )->set_keys( &the_byte, 1 ); 87 : } 88 : } 89 2369 : break; 90 1026 : case ResizeType: 91 1026 : { 92 1026 : Instruction *new_inst = output.add_instruction(); 93 1026 : new_inst->MutableExtension( resize )->set_width( my_it->resize.width ); 94 1026 : new_inst->MutableExtension( resize )->set_height( my_it->resize.height ); 95 : } 96 : break; 97 0 : default: 98 0 : assert( !"unexpected event type" ); 99 : break; 100 : } 101 : 102 3395 : my_it++; 103 : } 104 : 105 7874 : return output.SerializeAsString(); 106 3937 : } 107 : 108 2904 : void UserStream::apply_string( const string &diff ) 109 : { 110 2904 : ClientBuffers::UserMessage input; 111 2904 : fatal_assert( input.ParseFromString( diff ) ); 112 : 113 5192 : for ( int i = 0; i < input.instruction_size(); i++ ) { 114 2288 : if ( input.instruction( i ).HasExtension( keystroke ) ) { 115 1296 : string the_bytes = input.instruction( i ).GetExtension( keystroke ).keys(); 116 3658 : for ( unsigned int loc = 0; loc < the_bytes.size(); loc++ ) { 117 2362 : actions.push_back( UserEvent( UserByte( the_bytes.at( loc ) ) ) ); 118 : } 119 2288 : } else if ( input.instruction( i ).HasExtension( resize ) ) { 120 1984 : actions.push_back( UserEvent( Resize( input.instruction( i ).GetExtension( resize ).width(), 121 992 : input.instruction( i ).GetExtension( resize ).height() ) ) ); 122 : } 123 : } 124 2904 : } 125 : 126 1863 : const Parser::Action &UserStream::get_action( unsigned int i ) const 127 : { 128 1863 : switch( actions[ i ].type ) { 129 1367 : case UserByteType: 130 1367 : return actions[ i ].userbyte; 131 496 : case ResizeType: 132 496 : return actions[ i ].resize; 133 0 : default: 134 0 : assert( !"unexpected action type" ); 135 : static const Parser::Ignore nothing = Parser::Ignore(); 136 : return nothing; 137 : } 138 : }