'+e[0]+'
') + .append(l); + } + customIndex.append(ul); +}); + +}); \ No newline at end of file diff --git a/tools/python/doc/source/api_reference.rst b/tools/python/doc/source/api_reference.rst new file mode 100644 index 000000000..d08c68d77 --- /dev/null +++ b/tools/python/doc/source/api_reference.rst @@ -0,0 +1,24 @@ +API reference +============= + +Enums +----- + +.. include:: enums.rst + +Classes +------- + +.. container:: custom-index + + .. raw:: html + + + +.. currentmodule:: linphone + +.. automodule:: linphone + :members: + :undoc-members: + +.. autoattribute:: linphone.__version__ diff --git a/tools/python/doc/source/conf.py b/tools/python/doc/source/conf.py index 125e5c6d9..8dfeec972 100644 --- a/tools/python/doc/source/conf.py +++ b/tools/python/doc/source/conf.py @@ -29,7 +29,7 @@ import os # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ - 'sphinx.ext.autodoc', + 'sphinx.ext.autodoc' ] # Add any paths that contain templates here, relative to this directory. @@ -145,7 +145,9 @@ html_static_path = ['_static'] #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. -#html_sidebars = {} +html_sidebars = { + '**': ['localtoc.html', 'relations.html', 'searchbox.html'] +} # Additional templates that should be rendered to pages, maps page names to # template names. diff --git a/tools/python/doc/source/getting_started.rst b/tools/python/doc/source/getting_started.rst new file mode 100644 index 000000000..f0b830c59 --- /dev/null +++ b/tools/python/doc/source/getting_started.rst @@ -0,0 +1,44 @@ +Getting started +=============== + +Installing the Python module +---------------------------- + +You can install prebuilt packages of Linphone for Python. You will find the +releases at https://pypi.python.org/pypi/linphone. This includes only packages +for the Windows platform right now. The easiest way to install is to use pip, +eg.: + +.. code-block:: none + + > pip install linphone --pre + +You can also find nightly-built packages for Windows, Mac OS X and Linux at +https://www.linphone.org/snapshots/linphone-python/. + +Otherwise you can compile the Python module. To do so get the build system code +using the command: + +.. code-block:: none + + > git clone git://git.linphone.org/linphone-cmake-builder.git + +Then follow the instructions in the *README.python* file. + +Running some code +----------------- + +Here is a sample source code using PyQt4 that enables you to register on a SIP +server in just a few lines of code. This is a very basic example, but it shows +how to create a linphone.Core object that is the main object of Linphone. From +there, you can use the API reference below to use more advanced feature and +perform some SIP calls, use text messaging and more... + +.. literalinclude:: pyqt_linphone_example.py + +In the Linphone Python module package you installed previously you will also +find some unit tests that you can run. These unit tests will be located in the +*site-packages/linphone/unittests/* directory of Python installation where you +installed the Linphone Python module package. To run these unit tests, follow +the instructions contained in the README.txt file of this *unittests/* +directory. diff --git a/tools/python/doc/source/index.rst b/tools/python/doc/source/index.rst index f1c615162..a77d768f0 100644 --- a/tools/python/doc/source/index.rst +++ b/tools/python/doc/source/index.rst @@ -6,62 +6,12 @@ Linphone for Python documentation ================================= -Getting started ---------------- - -Installing the Python module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -You can install prebuilt packages of Linphone for Python. You will find the -releases at https://pypi.python.org/pypi/linphone. This includes only packages -for the Windows platform right now. The easiest way to install is to use pip, -eg.: - -.. code-block:: none - - > pip install linphone --pre - -You can also find nightly-built packages for Windows, Mac OS X and Linux at -https://www.linphone.org/snapshots/linphone-python/. - -Otherwise you can compile the Python module. To do so get the build system code -using the command: - -.. code-block:: none - - > git clone git://git.linphone.org/linphone-cmake-builder.git - -Then follow the instructions in the *README.python* file. - -Running some code -^^^^^^^^^^^^^^^^^ - -Here is a sample source code using PyQt4 that enables you to register on a SIP -server in just a few lines of code. This is a very basic example, but it shows -how to create a linphone.Core object that is the main object of Linphone. From -there, you can use the API reference below to use more advanced feature and -perform some SIP calls, use text messaging and more... - -.. literalinclude:: pyqt_linphone_example.py - -In the Linphone Python module package you installed previously you will also -find some unit tests that you can run. These unit tests will be located in the -*site-packages/linphone/unittests/* directory of Python installation where you -installed the Linphone Python module package. To run these unit tests, follow -the instructions contained in the README.txt file of this *unittests/* -directory. - -API reference -------------- - .. toctree:: :maxdepth: 2 + :numbered: -.. automodule:: linphone - :members: - :undoc-members: - -.. autoattribute:: linphone.__version__ + getting_started + api_reference Indices and tables diff --git a/tools/python/unittests/linphonetester.py b/tools/python/unittests/linphonetester.py index 76564d9b8..0d803c348 100644 --- a/tools/python/unittests/linphonetester.py +++ b/tools/python/unittests/linphonetester.py @@ -8,6 +8,7 @@ import sys import time +test_domain = "sipopen.example.org" test_username = "liblinphone_tester" test_password = "secret" test_route = "sip2.linphone.org" @@ -89,9 +90,9 @@ class AccountManager: @classmethod def account_created_on_server_cb(cls, lc, cfg, state, message): - if state == linphone.RegistrationState.RegistrationOk: + if state == linphone.RegistrationState.Ok: lc.user_data.created = True - elif state == linphone.RegistrationState.RegistrationCleared: + elif state == linphone.RegistrationState.Cleared: lc.user_data.done = True @classmethod @@ -134,7 +135,7 @@ class AccountManager: tmp_identity.set_header("X-Create-Account", "yes") cfg.identity = tmp_identity.as_string() server_addr = linphone.Address.new(refcfg.server_addr) - server_addr.transport = linphone.TransportType.TransportTcp; + server_addr.transport = linphone.TransportType.Tcp; server_addr.port = 0 cfg.server_addr = server_addr.as_string() cfg.expires = 3600 @@ -365,12 +366,12 @@ class CoreManager: lambda callee_manager, caller_manager: (callee_manager.stats.number_of_LinphoneCallStreamsRunning == initial_callee_stats.number_of_LinphoneCallStreamsRunning + 1) and \ (caller_manager.stats.number_of_LinphoneCallStreamsRunning == initial_caller_stats.number_of_LinphoneCallStreamsRunning + 1)) - if caller_manager.lc.media_encryption != linphone.MediaEncryption.MediaEncryptionNone and callee_manager.lc.media_encryption != linphone.MediaEncryption.MediaEncryptionNone: + if caller_manager.lc.media_encryption != linphone.MediaEncryption.MediaEncryptionNone and callee_manager.lc.media_encryption != linphone.MediaEncryption.None: # Wait for encryption to be on, in case of zrtp, it can take a few seconds - if caller_manager.lc.media_encryption == linphone.MediaEncryption.MediaEncryptionZRTP: + if caller_manager.lc.media_encryption == linphone.MediaEncryption.ZRTP: CoreManager.wait_for(callee_manager, caller_manager, lambda callee_manager, caller_manager: caller_manager.stats.number_of_LinphoneCallEncryptedOn == initial_caller_stats.number_of_LinphoneCallEncryptedOn + 1) - if callee_manager.lc.media_encryption == linphone.MediaEncryption.MediaEncryptionZRTP: + if callee_manager.lc.media_encryption == linphone.MediaEncryption.ZRTP: CoreManager.wait_for(callee_manager, caller_manager, lambda callee_manager, caller_manager: callee_manager.stats.number_of_LinphoneCallEncryptedOn == initial_callee_stats.number_of_LinphoneCallEncryptedOn + 1) assert_equals(callee_manager.lc.current_call.current_params.media_encryption, caller_manager.lc.media_encryption) @@ -389,15 +390,15 @@ class CoreManager: manager = lc.user_data linphonetester_logger.info("[TESTER] New registration state {state} for user id [{identity}] at proxy [{addr}]".format( state=linphone.RegistrationState.string(state), identity=cfg.identity, addr=cfg.server_addr)) - if state == linphone.RegistrationState.RegistrationNone: + if state == linphone.RegistrationState.None: manager.stats.number_of_LinphoneRegistrationNone += 1 - elif state == linphone.RegistrationState.RegistrationProgress: + elif state == linphone.RegistrationState.Progress: manager.stats.number_of_LinphoneRegistrationProgress += 1 - elif state == linphone.RegistrationState.RegistrationOk: + elif state == linphone.RegistrationState.Ok: manager.stats.number_of_LinphoneRegistrationOk += 1 - elif state == linphone.RegistrationState.RegistrationCleared: + elif state == linphone.RegistrationState.Cleared: manager.stats.number_of_LinphoneRegistrationCleared += 1 - elif state == linphone.RegistrationState.RegistrationFailed: + elif state == linphone.RegistrationState.Failed: manager.stats.number_of_LinphoneRegistrationFailed += 1 else: raise Exception("Unexpected registration state") @@ -415,45 +416,45 @@ class CoreManager: to_address = call.call_log.to_address.as_string() from_address = call.call_log.from_address.as_string() direction = "Outgoing" - if call.call_log.dir == linphone.CallDir.CallIncoming: + if call.call_log.dir == linphone.CallDir.Incoming: direction = "Incoming" linphonetester_logger.info("[TESTER] {direction} call from [{from_address}] to [{to_address}], new state is [{state}]".format( direction=direction, from_address=from_address, to_address=to_address, state=linphone.CallState.string(state))) - if state == linphone.CallState.CallIncomingReceived: + if state == linphone.CallState.IncomingReceived: manager.stats.number_of_LinphoneCallIncomingReceived += 1 - elif state == linphone.CallState.CallOutgoingInit: + elif state == linphone.CallState.OutgoingInit: manager.stats.number_of_LinphoneCallOutgoingInit += 1 - elif state == linphone.CallState.CallOutgoingProgress: + elif state == linphone.CallState.OutgoingProgress: manager.stats.number_of_LinphoneCallOutgoingProgress += 1 - elif state == linphone.CallState.CallOutgoingRinging: + elif state == linphone.CallState.OutgoingRinging: manager.stats.number_of_LinphoneCallOutgoingRinging += 1 - elif state == linphone.CallState.CallOutgoingEarlyMedia: + elif state == linphone.CallState.OutgoingEarlyMedia: manager.stats.number_of_LinphoneCallOutgoingEarlyMedia += 1 - elif state == linphone.CallState.CallConnected: + elif state == linphone.CallState.Connected: manager.stats.number_of_LinphoneCallConnected += 1 - elif state == linphone.CallState.CallStreamsRunning: + elif state == linphone.CallState.StreamsRunning: manager.stats.number_of_LinphoneCallStreamsRunning += 1 - elif state == linphone.CallState.CallPausing: + elif state == linphone.CallState.Pausing: manager.stats.number_of_LinphoneCallPausing += 1 - elif state == linphone.CallState.CallPaused: + elif state == linphone.CallState.Paused: manager.stats.number_of_LinphoneCallPaused += 1 - elif state == linphone.CallState.CallResuming: + elif state == linphone.CallState.Resuming: manager.stats.number_of_LinphoneCallResuming += 1 - elif state == linphone.CallState.CallRefered: + elif state == linphone.CallState.Refered: manager.stats.number_of_LinphoneCallRefered += 1 - elif state == linphone.CallState.CallError: + elif state == linphone.CallState.Error: manager.stats.number_of_LinphoneCallError += 1 - elif state == linphone.CallState.CallEnd: + elif state == linphone.CallState.End: manager.stats.number_of_LinphoneCallEnd += 1 - elif state == linphone.CallState.CallPausedByRemote: + elif state == linphone.CallState.PausedByRemote: manager.stats.number_of_LinphoneCallPausedByRemote += 1 - elif state == linphone.CallState.CallUpdatedByRemote: + elif state == linphone.CallState.UpdatedByRemote: manager.stats.number_of_LinphoneCallUpdatedByRemote += 1 - elif state == linphone.CallState.CallIncomingEarlyMedia: + elif state == linphone.CallState.IncomingEarlyMedia: manager.stats.number_of_LinphoneCallIncomingEarlyMedia += 1 - elif state == linphone.CallState.CallUpdating: + elif state == linphone.CallState.Updating: manager.stats.number_of_LinphoneCallUpdating += 1 - elif state == linphone.CallState.CallReleased: + elif state == linphone.CallState.Released: manager.stats.number_of_LinphoneCallReleased += 1 else: raise Exception("Unexpected call state") @@ -489,63 +490,63 @@ class CoreManager: manager.stats.number_of_NotifyReceived += 1 manager.stats.last_received_presence = lf.presence_model acttype = manager.stats.last_received_presence.activity.type - if acttype == linphone.PresenceActivityType.PresenceActivityOffline: + if acttype == linphone.PresenceActivityType.Offline: manager.stats.number_of_LinphonePresenceActivityOffline += 1 - elif acttype == linphone.PresenceActivityType.PresenceActivityOnline: + elif acttype == linphone.PresenceActivityType.Online: manager.stats.number_of_LinphonePresenceActivityOnline += 1 - elif acttype == linphone.PresenceActivityType.PresenceActivityAppointment: + elif acttype == linphone.PresenceActivityType.Appointment: manager.stats.number_of_LinphonePresenceActivityAppointment += 1 - elif acttype == linphone.PresenceActivityType.PresenceActivityAway: + elif acttype == linphone.PresenceActivityType.Away: manager.stats.number_of_LinphonePresenceActivityAway += 1 - elif acttype == linphone.PresenceActivityType.PresenceActivityBreakfast: + elif acttype == linphone.PresenceActivityType.Breakfast: manager.stats.number_of_LinphonePresenceActivityBreakfast += 1 - elif acttype == linphone.PresenceActivityType.PresenceActivityBusy: + elif acttype == linphone.PresenceActivityType.Busy: manager.stats.number_of_LinphonePresenceActivityBusy += 1 - elif acttype == linphone.PresenceActivityType.PresenceActivityDinner: + elif acttype == linphone.PresenceActivityType.Dinner: manager.stats.number_of_LinphonePresenceActivityDinner += 1 - elif acttype == linphone.PresenceActivityType.PresenceActivityHoliday: + elif acttype == linphone.PresenceActivityType.Holiday: manager.stats.number_of_LinphonePresenceActivityHoliday += 1 - elif acttype == linphone.PresenceActivityType.PresenceActivityInTransit: + elif acttype == linphone.PresenceActivityType.InTransit: manager.stats.number_of_LinphonePresenceActivityInTransit += 1 - elif acttype == linphone.PresenceActivityType.PresenceActivityLookingForWork: + elif acttype == linphone.PresenceActivityType.LookingForWork: manager.stats.number_of_LinphonePresenceActivityLookingForWork += 1 - elif acttype == linphone.PresenceActivityType.PresenceActivityLunch: + elif acttype == linphone.PresenceActivityType.Lunch: manager.stats.number_of_LinphonePresenceActivityLunch += 1 - elif acttype == linphone.PresenceActivityType.PresenceActivityMeal: + elif acttype == linphone.PresenceActivityType.Meal: manager.stats.number_of_LinphonePresenceActivityMeal += 1 - elif acttype == linphone.PresenceActivityType.PresenceActivityMeeting: + elif acttype == linphone.PresenceActivityType.Meeting: manager.stats.number_of_LinphonePresenceActivityMeeting += 1 - elif acttype == linphone.PresenceActivityType.PresenceActivityOnThePhone: + elif acttype == linphone.PresenceActivityType.OnThePhone: manager.stats.number_of_LinphonePresenceActivityOnThePhone += 1 - elif acttype == linphone.PresenceActivityType.PresenceActivityOther: + elif acttype == linphone.PresenceActivityType.Other: manager.stats.number_of_LinphonePresenceActivityOther += 1 - elif acttype == linphone.PresenceActivityType.PresenceActivityPerformance: + elif acttype == linphone.PresenceActivityType.Performance: manager.stats.number_of_LinphonePresenceActivityPerformance += 1 - elif acttype == linphone.PresenceActivityType.PresenceActivityPermanentAbsence: + elif acttype == linphone.PresenceActivityType.PermanentAbsence: manager.stats.number_of_LinphonePresenceActivityPermanentAbsence += 1 - elif acttype == linphone.PresenceActivityType.PresenceActivityPlaying: + elif acttype == linphone.PresenceActivityType.Playing: manager.stats.number_of_LinphonePresenceActivityPlaying += 1 - elif acttype == linphone.PresenceActivityType.PresenceActivityPresentation: + elif acttype == linphone.PresenceActivityType.Presentation: manager.stats.number_of_LinphonePresenceActivityPresentation += 1 - elif acttype == linphone.PresenceActivityType.PresenceActivityShopping: + elif acttype == linphone.PresenceActivityType.Shopping: manager.stats.number_of_LinphonePresenceActivityShopping += 1 - elif acttype == linphone.PresenceActivityType.PresenceActivitySleeping: + elif acttype == linphone.PresenceActivityType.Sleeping: manager.stats.number_of_LinphonePresenceActivitySleeping += 1 - elif acttype == linphone.PresenceActivityType.PresenceActivitySpectator: + elif acttype == linphone.PresenceActivityType.Spectator: manager.stats.number_of_LinphonePresenceActivitySpectator += 1 - elif acttype == linphone.PresenceActivityType.PresenceActivitySteering: + elif acttype == linphone.PresenceActivityType.Steering: manager.stats.number_of_LinphonePresenceActivitySteering += 1 - elif acttype == linphone.PresenceActivityType.PresenceActivityTravel: + elif acttype == linphone.PresenceActivityType.Travel: manager.stats.number_of_LinphonePresenceActivityTravel += 1 - elif acttype == linphone.PresenceActivityType.PresenceActivityTV: + elif acttype == linphone.PresenceActivityType.TV: manager.stats.number_of_LinphonePresenceActivityTV += 1 - elif acttype == linphone.PresenceActivityType.PresenceActivityUnknown: + elif acttype == linphone.PresenceActivityType.Unknown: manager.stats.number_of_LinphonePresenceActivityUnknown += 1 - elif acttype == linphone.PresenceActivityType.PresenceActivityVacation: + elif acttype == linphone.PresenceActivityType.Vacation: manager.stats.number_of_LinphonePresenceActivityVacation += 1 - elif acttype == linphone.PresenceActivityType.PresenceActivityWorking: + elif acttype == linphone.PresenceActivityType.Working: manager.stats.number_of_LinphonePresenceActivityWorking += 1 - elif acttype == linphone.PresenceActivityType.PresenceActivityWorship: + elif acttype == linphone.PresenceActivityType.Worship: manager.stats.number_of_LinphonePresenceActivityWorship += 1 def __init__(self, rc_file = None, check_for_proxies = True, vtable = {}): diff --git a/tools/python/unittests/test_call.py b/tools/python/unittests/test_call.py index daf1f8e83..4357f245c 100644 --- a/tools/python/unittests/test_call.py +++ b/tools/python/unittests/test_call.py @@ -17,11 +17,11 @@ class TestCall: assert_equals(CoreManager.wait_for_until(pauline, marie, lambda pauline, marie: pauline.stats.number_of_LinphoneCallError == 1, 33000), True) assert_equals(pauline.stats.number_of_LinphoneCallError, 1) #FIXME http://git.linphone.org/mantis/view.php?id=757 - #assert_equals(out_call.reason, linphone.Reason.ReasonBusy) + #assert_equals(out_call.reason, linphone.Reason.Busy) if len(pauline.lc.call_logs) > 0: out_call_log = pauline.lc.call_logs[0] assert out_call_log is not None - assert_equals(out_call_log.status, linphone.CallStatus.CallAborted) + assert_equals(out_call_log.status, linphone.CallStatus.Aborted) marie.stop() pauline.stop() @@ -38,8 +38,8 @@ class TestCall: assert_equals(CoreManager.wait_for(pauline, marie, lambda pauline, marie: pauline.stats.number_of_LinphoneCallReleased == 1), True) assert_equals(marie.stats.number_of_LinphoneCallEnd, 1) assert_equals(pauline.stats.number_of_LinphoneCallEnd, 1) - assert_equals(in_call.reason, linphone.Reason.ReasonDeclined) - assert_equals(out_call.reason, linphone.Reason.ReasonDeclined) + assert_equals(in_call.reason, linphone.Reason.Declined) + assert_equals(out_call.reason, linphone.Reason.Declined) marie.stop() pauline.stop() @@ -97,7 +97,7 @@ class TestCall: # flexisip will retain the 488 until the "urgent reply" timeout arrives. assert_equals(CoreManager.wait_for_until(pauline, marie, lambda pauline, marie: pauline.stats.number_of_LinphoneCallError == 1, 7000), True) - assert_equals(out_call.reason, linphone.Reason.ReasonNotAcceptable) + assert_equals(out_call.reason, linphone.Reason.NotAcceptable) assert_equals(marie.stats.number_of_LinphoneCallIncomingReceived, 0) assert_equals(marie.stats.number_of_LinphoneCallReleased, 0) marie.stop() diff --git a/tools/python/unittests/test_message.py b/tools/python/unittests/test_message.py index ebd53fc66..8cfb05c87 100644 --- a/tools/python/unittests/test_message.py +++ b/tools/python/unittests/test_message.py @@ -1,8 +1,10 @@ from nose.tools import assert_equals from copy import deepcopy +import filecmp import linphone from linphonetester import * import os +import os.path import time @@ -12,30 +14,74 @@ class TestMessage: def msg_state_changed(cls, msg, state): stats = msg.chat_room.core.user_data.stats linphonetester_logger.info("[TESTER] Message [{text}] [{state}]".format(text=msg.text, state=linphone.ChatMessageState.string(state))) - if state == linphone.ChatMessageState.ChatMessageStateDelivered: + if state == linphone.ChatMessageState.Delivered: stats.number_of_LinphoneMessageDelivered += 1 - elif state == linphone.ChatMessageState.ChatMessageStateNotDelivered: + elif state == linphone.ChatMessageState.NotDelivered: stats.number_of_LinphoneMessageNotDelivered += 1 - elif state == linphone.ChatMessageState.ChatMessageStateInProgress: + elif state == linphone.ChatMessageState.InProgress: stats.number_of_LinphoneMessageInProgress += 1 - elif state == linphone.ChatMessageState.ChatMessageStateFileTransferError: + elif state == linphone.ChatMessageState.FileTransferError: stats.number_of_LinphoneMessageNotDelivered += 1 else: linphonetester_logger.error("[TESTER] Unexpected state [{state}] for message [{msg}]".format(msg=msg, state=linphone.ChatMessageState.string(state))) @classmethod - def file_transfer_received(cls, msg, content, buf, size): - print buf, size + def file_transfer_progress_indication(cls, msg, content, offset, total): stats = msg.chat_room.core.user_data.stats - if msg.user_data is None: - msg.user_data = open('receive_file.dump', 'wb') - msg.user_data.write(buf) - else: - if size == 0: # Transfer complete - stats.number_of_LinphoneMessageExtBodyReceived += 1 - msg.user_data.close() - else: # Store content - msg.user_data.write(buf) + progress = int((offset * 100) / total) + direction = 'received' + tofrom = 'from' + address = msg.from_address + if msg.outgoing: + direction = 'sent' + tofrom = 'to' + address = msg.to_address + linphonetester_logger.info("[TESTER] File transfer [{progress}%] {direction} of type [{type}/{subtype}] {tofrom} {address}".format( + progress=progress, direction=direction, type=content.type, subtype=content.subtype, tofrom=tofrom, address=address.as_string())); + stats.progress_of_LinphoneFileTransfer = progress + + @classmethod + def file_transfer_send(cls, msg, content, offset, size): + send_filepath = msg.user_data + send_filesize = os.path.getsize(send_filepath) + if offset >= send_filesize: + return linphone.Buffer.new() # end of file + f = open(send_filepath, 'rb') + f.seek(offset, 0) + if (send_filesize - offset) < size: + size = send_filesize - offset + lb = linphone.Buffer.new_from_data(bytearray(f.read(size))) + f.close() + return lb + + @classmethod + def file_transfer_recv(cls, msg, content, buf): + receive_filepath = msg.user_data + stats = msg.chat_room.core.user_data.stats + if buf.empty: # Transfer complete + stats.number_of_LinphoneMessageExtBodyReceived += 1 + else: # Store content + f = open(receive_filepath, 'ab') + f.write(buf.content) + f.close() + + @classmethod + def memory_file_transfer_send(cls, msg, content, offset, size): + send_buf = msg.user_data + send_size = len(send_buf) + if offset >= send_size: + return linphone.Buffer.new() + if (send_size - offset) < size: + size = send_size - offset + return linphone.Buffer.new_from_string(send_buf[offset:offset+size]) + + @classmethod + def memory_file_transfer_recv(cls, msg, content, buf): + stats = msg.chat_room.core.user_data.stats + if buf.empty: # Transfer complete + stats.number_of_LinphoneMessageExtBodyReceived += 1 + else: # Store content + msg.user_data += buf.string_content def wait_for_server_to_purge_messages(self, manager1, manager2): # Wait a little bit just to have time to purge message stored in the server @@ -49,7 +95,7 @@ class TestMessage: chat_room = pauline.lc.get_chat_room(marie.identity) self.wait_for_server_to_purge_messages(marie, pauline) msg = chat_room.create_message("Bla bla bla bla") - chat_room.send_message2(msg, None, None) + chat_room.send_chat_message(msg) assert_equals(CoreManager.wait_for(pauline, marie, lambda pauline, marie: marie.stats.number_of_LinphoneMessageReceived == 1), True) assert marie.lc.get_chat_room(pauline.identity) is not None marie.stop() @@ -63,40 +109,108 @@ class TestMessage: self.wait_for_server_to_purge_messages(marie, pauline) assert_equals(CoreManager.call(marie, pauline), True) msg = chat_room.create_message("Bla bla bla bla") - chat_room.send_message2(msg, None, None) + chat_room.send_chat_message(msg) assert_equals(CoreManager.wait_for(pauline, marie, lambda pauline, marie: marie.stats.number_of_LinphoneMessageReceived == 1), True) assert marie.lc.get_chat_room(pauline.identity) is not None marie.stop() pauline.stop() def test_file_transfer_message(self): - big_file = "big file" marie = CoreManager('marie_rc') pauline = CoreManager('pauline_rc') - while len(big_file) < 128000: - big_file += big_file - l = list(big_file) - l[0] = 'S' - l[-1] = 'E' - big_file = ''.join(l) + send_filepath = os.path.join(tester_resources_path, 'images', 'nowebcamCIF.jpg') + receive_filepath = 'receive_file.dump' pauline.lc.file_transfer_server = "https://www.linphone.org:444/lft.php" chat_room = pauline.lc.get_chat_room(marie.identity) content = pauline.lc.create_content() - content.type = 'text' - content.subtype = 'plain' - content.size = len(big_file) # total size to be transfered - content.name = 'bigfile.txt' + content.type = 'image' + content.subtype = 'jpeg' + content.size = os.path.getsize(send_filepath) # total size to be transfered + content.name = 'nowebcamCIF.jpg' message = chat_room.create_file_transfer_message(content) + message.user_data = send_filepath self.wait_for_server_to_purge_messages(marie, pauline) message.callbacks.msg_state_changed = TestMessage.msg_state_changed + message.callbacks.file_transfer_send = TestMessage.file_transfer_send chat_room.send_chat_message(message) assert_equals(CoreManager.wait_for(pauline, marie, lambda pauline, marie: marie.stats.number_of_LinphoneMessageReceivedWithFile == 1), True) if marie.stats.last_received_chat_message is not None: cbs = marie.stats.last_received_chat_message.callbacks cbs.msg_state_changed = TestMessage.msg_state_changed - cbs.file_transfer_recv = TestMessage.file_transfer_received + cbs.file_transfer_recv = TestMessage.file_transfer_recv + marie.stats.last_received_chat_message.user_data = receive_filepath marie.stats.last_received_chat_message.download_file() assert_equals(CoreManager.wait_for(pauline, marie, lambda pauline, marie: marie.stats.number_of_LinphoneMessageExtBodyReceived == 1), True) assert_equals(pauline.stats.number_of_LinphoneMessageInProgress, 1) assert_equals(pauline.stats.number_of_LinphoneMessageDelivered, 1) assert_equals(marie.stats.number_of_LinphoneMessageExtBodyReceived, 1) + assert_equals(filecmp.cmp(send_filepath, receive_filepath, shallow=False), True) + if os.path.exists(receive_filepath): + os.remove(receive_filepath) + + def test_small_file_transfer_message(self): + send_buf = "small file" + marie = CoreManager('marie_rc') + pauline = CoreManager('pauline_rc') + while len(send_buf) < 160: + send_buf += send_buf + l = list(send_buf[0:160]) + l[0] = 'S' + l[-1] = 'E' + send_buf = ''.join(l) + pauline.lc.file_transfer_server = "https://www.linphone.org:444/lft.php" + chat_room = pauline.lc.get_chat_room(marie.identity) + content = pauline.lc.create_content() + content.type = 'text' + content.subtype = 'plain' + content.size = len(send_buf) # total size to be transfered + content.name = 'small_file.txt' + message = chat_room.create_file_transfer_message(content) + message.user_data = send_buf + self.wait_for_server_to_purge_messages(marie, pauline) + message.callbacks.msg_state_changed = TestMessage.msg_state_changed + message.callbacks.file_transfer_send = TestMessage.memory_file_transfer_send + chat_room.send_chat_message(message) + assert_equals(CoreManager.wait_for(pauline, marie, lambda pauline, marie: marie.stats.number_of_LinphoneMessageReceivedWithFile == 1), True) + if marie.stats.last_received_chat_message is not None: + cbs = marie.stats.last_received_chat_message.callbacks + cbs.msg_state_changed = TestMessage.msg_state_changed + cbs.file_transfer_recv = TestMessage.memory_file_transfer_recv + marie.stats.last_received_chat_message.user_data = '' + marie.stats.last_received_chat_message.download_file() + assert_equals(CoreManager.wait_for(pauline, marie, lambda pauline, marie: marie.stats.number_of_LinphoneMessageExtBodyReceived == 1), True) + assert_equals(pauline.stats.number_of_LinphoneMessageInProgress, 1) + assert_equals(pauline.stats.number_of_LinphoneMessageDelivered, 1) + assert_equals(marie.stats.number_of_LinphoneMessageExtBodyReceived, 1) + assert_equals(send_buf, marie.stats.last_received_chat_message.user_data) + + def test_file_transfer_message_upload_cancelled(self): + send_buf = "big file" + marie = CoreManager('marie_rc') + pauline = CoreManager('pauline_rc') + while len(send_buf) < 128000: + send_buf += send_buf + l = list(send_buf[0:128000]) + l[0] = 'S' + l[-1] = 'E' + send_buf = ''.join(l) + pauline.lc.file_transfer_server = "https://www.linphone.org:444/lft.php" + chat_room = pauline.lc.get_chat_room(marie.identity) + content = pauline.lc.create_content() + content.type = 'text' + content.subtype = 'plain' + content.size = len(send_buf) # total size to be transfered + content.name = 'big_file.txt' + message = chat_room.create_file_transfer_message(content) + message.user_data = send_buf + self.wait_for_server_to_purge_messages(marie, pauline) + message.callbacks.msg_state_changed = TestMessage.msg_state_changed + message.callbacks.file_transfer_send = TestMessage.memory_file_transfer_send + message.callbacks.file_transfer_progress_indication = TestMessage.file_transfer_progress_indication + chat_room.send_chat_message(message) + # Wait for file to be at least 50% uploaded and cancel the transfer + assert_equals(CoreManager.wait_for(pauline, marie, lambda pauline, marie: pauline.stats.progress_of_LinphoneFileTransfer >= 50), True) + message.cancel_file_transfer() + assert_equals(CoreManager.wait_for(pauline, marie, lambda pauline, marie: pauline.stats.number_of_LinphoneMessageNotDelivered == 1), True) + assert_equals(pauline.stats.number_of_LinphoneMessageNotDelivered, 1) + assert_equals(marie.stats.number_of_LinphoneMessageExtBodyReceived, 0) diff --git a/tools/python/unittests/test_register.py b/tools/python/unittests/test_register.py index 2a42194f0..be6918251 100644 --- a/tools/python/unittests/test_register.py +++ b/tools/python/unittests/test_register.py @@ -18,9 +18,10 @@ class RegisterCoreManager(CoreManager): vtable['auth_info_requested'] = RegisterCoreManager.auth_info_requested CoreManager.__init__(self, vtable=vtable) - def register_with_refresh(self, refresh, domain, route, late_auth_info = False, expected_final_state = linphone.RegistrationState.RegistrationOk): + def register_with_refresh_base(self, refresh, domain, route, late_auth_info = False, transport = linphone.SipTransports(5070, 5070, 5071, 0), expected_final_state = linphone.RegistrationState.Ok): assert self.lc is not None self.stats.reset() + self.lc.sip_transports = transport proxy_cfg = self.lc.create_proxy_config() from_address = create_address(domain) proxy_cfg.identity = from_address.as_string() @@ -35,32 +36,30 @@ class RegisterCoreManager(CoreManager): self.lc.add_proxy_config(proxy_cfg) self.lc.default_proxy_config = proxy_cfg - #linphone_core_set_sip_transports(lc,&transport); - retry = 0 expected_count = 1 if refresh: expected_count += 1 max_retry = 110 - if expected_final_state == linphone.RegistrationState.RegistrationProgress: + if expected_final_state == linphone.RegistrationState.Progress: max_retry += 200 while self.stats.number_of_LinphoneRegistrationOk < expected_count and retry < max_retry: retry += 1 self.lc.iterate() - if self.stats.number_of_auth_info_requested > 0 and proxy_cfg.state == linphone.RegistrationState.RegistrationFailed and late_auth_info: + if self.stats.number_of_auth_info_requested > 0 and proxy_cfg.state == linphone.RegistrationState.Failed and late_auth_info: if len(self.lc.auth_info_list) == 0: - assert_equals(proxy_cfg.error, linphone.Reason.ReasonUnauthorized) + assert_equals(proxy_cfg.error, linphone.Reason.Unauthorized) info = linphone.AuthInfo.new(test_username, None, test_password, None, None, None) # Create authentication structure from identity self.lc.add_auth_info(info) - if proxy_cfg.error == linphone.Reason.ReasonForbidden or \ - (self.stats.number_of_auth_info_requested > 2 and proxy_cfg.error == linphone.Reason.ReasonUnauthorized): + if proxy_cfg.error == linphone.Reason.Forbidden or \ + (self.stats.number_of_auth_info_requested > 2 and proxy_cfg.error == linphone.Reason.Unauthorized): break time.sleep(0.1) assert_equals(proxy_cfg.state, expected_final_state) assert_equals(self.stats.number_of_LinphoneRegistrationNone, 0) assert self.stats.number_of_LinphoneRegistrationProgress >= 1 - if expected_final_state == linphone.RegistrationState.RegistrationOk: + if expected_final_state == linphone.RegistrationState.Ok: assert_equals(self.stats.number_of_LinphoneRegistrationOk, expected_count) expected_failed = 0 if late_auth_info: @@ -69,6 +68,8 @@ class RegisterCoreManager(CoreManager): else: assert_equals(self.stats.number_of_LinphoneRegistrationCleared, 0) + def register_with_refresh(self, refresh, domain, route, late_auth_info = False, transport = linphone.SipTransports(5070, 5070, 5071, 0), expected_final_state = linphone.RegistrationState.Ok): + self.register_with_refresh_base(refresh, domain, route, late_auth_info, expected_final_state = expected_final_state) self.stop() # Not testable as the callbacks can not be called once the core destruction has started #assert_equals(self.stats.number_of_LinphoneRegistrationCleared, 1) @@ -80,3 +81,67 @@ class TestRegister: cm = RegisterCoreManager() cm.register_with_refresh(False, None, None) assert_equals(cm.stats.number_of_auth_info_requested, 0) + + def test_simple_unregister(self): + cm = RegisterCoreManager() + cm.register_with_refresh_base(False, None, None) + pc = cm.lc.default_proxy_config + pc.edit() + cm.stats.reset() # clear stats + # nothing is supposed to arrive until done + assert_equals(CoreManager.wait_for_until(cm, cm, lambda cm1, cm2: cm1.stats.number_of_LinphoneRegistrationCleared == 1, 3000), False) + pc.register_enabled = False + pc.done() + assert_equals(CoreManager.wait_for(cm, cm, lambda cm1, cm2: cm1.stats.number_of_LinphoneRegistrationCleared == 1), True) + + def test_simple_tcp_register(self): + cm = RegisterCoreManager() + cm.register_with_refresh(False, test_domain, "sip:{route};transport=tcp".format(route=test_route)) + + def test_simple_tcp_register_compatibility_mode(self): + cm = RegisterCoreManager() + cm.register_with_refresh(False, test_domain, "sip:{route}".format(route=test_route), transport=linphone.SipTransports(0, 5070, 0, 0)) + + def test_simple_tls_register(self): + cm = RegisterCoreManager() + cm.register_with_refresh(False, test_domain, "sip:{route};transport=tls".format(route=test_route)) + + def test_tls_register_with_alt_name(self): + cm = CoreManager('pauline_alt_rc', False) + cm.lc.root_ca = os.path.join(tester_resources_path, 'certificates', 'cn', 'cafile.pem') + cm.lc.refresh_registers() + assert_equals(CoreManager.wait_for(cm, cm, lambda cm1, cm2: cm1.stats.number_of_LinphoneRegistrationOk == 1), True) + assert_equals(cm.stats.number_of_LinphoneRegistrationFailed, 0) + + def test_tls_wildcard_register(self): + cm = CoreManager('pauline_wild_rc', False) + cm.lc.root_ca = os.path.join(tester_resources_path, 'certificates', 'cn', 'cafile.pem') + cm.lc.refresh_registers() + assert_equals(CoreManager.wait_for(cm, cm, lambda cm1, cm2: cm1.stats.number_of_LinphoneRegistrationOk == 2), True) + assert_equals(cm.stats.number_of_LinphoneRegistrationFailed, 0) + + def test_tls_certificate_failure(self): + cm = CoreManager('pauline_rc', False) + cm.lc.root_ca = os.path.join(tester_resources_path, 'certificates', 'cn', 'agent.pem') # bad root ca + cm.lc.network_reachable = True + assert_equals(CoreManager.wait_for(cm, cm, lambda cm1, cm2: cm1.stats.number_of_LinphoneRegistrationFailed == 1), True) + cm.lc.root_ca = None # no root ca + cm.lc.refresh_registers() + assert_equals(CoreManager.wait_for(cm, cm, lambda cm1, cm2: cm1.stats.number_of_LinphoneRegistrationFailed == 2), True) + cm.lc.root_ca = os.path.join(tester_resources_path, 'certificates', 'cn', 'cafile.pem') # good root ca + cm.lc.refresh_registers() + assert_equals(CoreManager.wait_for(cm, cm, lambda cm1, cm2: cm1.stats.number_of_LinphoneRegistrationOk == 1), True) + assert_equals(cm.stats.number_of_LinphoneRegistrationFailed, 2) + + def test_tls_with_non_tls_server(self): + cm = CoreManager('marie_rc', False) + cm.lc.sip_transport_timeout = 3000 + pc = cm.lc.default_proxy_config + pc.edit() + addr = linphone.Address.new(pc.server_addr) + port = addr.port + if port <= 0: + port = 5060 + pc.server_addr = "sip:{domain}:{port};transport=tls".format(domain=addr.domain, port=port) + pc.done() + assert_equals(CoreManager.wait_for_until(cm, cm, lambda cm1, cm2: cm1.stats.number_of_LinphoneRegistrationFailed == 1, 5000), True) diff --git a/tools/python/unittests/test_setup.py b/tools/python/unittests/test_setup.py index 9afcda434..9fcafa8b8 100644 --- a/tools/python/unittests/test_setup.py +++ b/tools/python/unittests/test_setup.py @@ -5,6 +5,13 @@ import os class TestSetup: + def test_address(self): + create_address(None) + + def test_version(self): + lc = linphone.Core.new({}, None, None) + assert_equals(lc.version.find("unknown"), -1) + def test_address(self): create_address(None) @@ -14,6 +21,23 @@ class TestSetup: if lc is not None: lc.verify_server_certificates(False) + def test_random_transport(self): + lc = linphone.Core.new({}, None, None) + assert lc is not None + tr = lc.sip_transports + assert_equals(tr.udp_port, 5060) # default config + assert_equals(tr.tcp_port, 5060) # default config + tr.udp_port = -1 + tr.tcp_port = -1 + tr.tls_port = -1 + lc.sip_transports = tr + tr = lc.sip_transports + assert tr.udp_port != 5060 # default config + assert tr.tcp_port != 5060 # default config + assert_equals(lc.config.get_int('sip', 'sip_port', -2), -1) + assert_equals(lc.config.get_int('sip', 'sip_tcp_port', -2), -1) + assert_equals(lc.config.get_int('sip', 'sip_tls_port', -2), -1) + def test_interpret_url(self): lc = linphone.Core.new({}, None, None) assert lc is not None @@ -32,6 +56,22 @@ class TestSetup: conf = linphone.LpConfig.new_from_buffer(buffer_linebreaks) assert_equals(conf.get_string("buffer_linebreaks", "test", ""), "ok") + def test_lpconfig_zerolen_value_from_buffer(self): + zerolen = "[test]\nzero_len=\nnon_zero_len=test" + conf = linphone.LpConfig.new_from_buffer(zerolen) + assert_equals(conf.get_string("test", "zero_len", "LOL"), "LOL") + assert_equals(conf.get_string("test", "non_zero_len", ""), "test") + conf.set_string("test", "non_zero_len", "") # should remove "non_zero_len" + assert_equals(conf.get_string("test", "non_zero_len", "LOL"), "LOL") + + def test_lpconfig_zerolen_value_from_file(self): + conf = linphone.LpConfig.new_with_factory(None, os.path.join(tester_resources_path, 'rcfiles', 'zero_length_params_rc')) + assert_equals(conf.get_string("test", "zero_len", "LOL"), "LOL") + # non_zero_len=test -> should return test + assert_equals(conf.get_string("test", "non_zero_len", ""), "test") + conf.set_string("test", "non_zero_len", "") # should remove "non_zero_len" + assert_equals(conf.get_string("test", "non_zero_len", "LOL"), "LOL") + def test_create_chat_room(self): lc = linphone.Core.new({}, None, None) assert lc is not None